SitePoint Sponsor

User Tag List

Page 4 of 4 FirstFirst 1234
Results 76 to 83 of 83
  1. #76
    SitePoint Enthusiast
    Join Date
    Jun 2007
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by cuberoot View Post

    PHP Code:
    $view = new PageView();
    $view->addChild(new WelcomeMessagesView(), 'welcomeMessages');
    // ForumPostsView might not return output, but it's still a part of this view
    $view->addChild(new ForumPostsView(), 'forumPosts');
    $view->accept($renderer = new HtmlPageRenderer());
    echo 
    $renderer->render($locator); 
    Can you say where the PageView is created? Inside the frontcontroller or where? And if so how does the frontcontroller know what to add to the pageview? (I mean the views to be added are not always static so where put the logic to choose what to add?)
    And can you maybe show a basic implementation of View::accept(Renderer $renderer) and Renderer::render(Locator $locator)?

    I really like this concept you showed us but I cant imagine the concrete implementation. Any help would be really nice!

  2. #77
    SitePoint Addict
    Join Date
    Feb 2007
    Posts
    251
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here's a rough attempt at an implementation.

    Reflecting the hierarchical nature of the view in the render variables is left as an exercise for the reader, i.e., myc

    Would love to see what anybody else comes up with.

    PHP Code:
    class ServiceLocator {
        
    /**
         * @return Session
         */
        
    function session() {
            return new 
    Session();
        }
    }
    class 
    Session {
        
    /**
         * @return User
         */
        
    function user() {
            return new 
    User();
        }
    }
    class 
    User {
        function 
    getUsername() {
            return 
    'usernameTest';
        }
    }
    class 
    Factory {
        
    /**
         * @return ViewFactory
         */
        
    function views() {
            return new 
    ViewFactory();
        }
    }
    class 
    ViewFactory {
        
    /**
         * @return PageView
         */
        
    function homePage() {
            return 
    $this->page()
                ->
    addChild($this->welcomeMessages())
                ->
    addChild($this->forumPosts());
        }
        
    /**
         * @return ForumPostsView
         */
        
    function forumPosts() {
            return new 
    ForumPostsView();
        }
        
    /**
         * @return PageView
         */
        
    function page() {
            return new 
    PageView();
        }
        
    /**
         * @return WelcomeMessagesView
         */
        
    function welcomeMessages() {
            return new 
    WelcomeMessagesView();
        }
    }
    abstract class 
    View {
        abstract function 
    execute(ServiceLocator $locator);
        function 
    accept(Renderer $renderer) {
            
    $renderer->visit($this);
        }
    }
    abstract class 
    CompositeView extends View {
        private 
    $children = array();
        
    /**
         * @return View
         */
        
    function addChild(View $view) {
            
    $this->children[] = $view;
            return 
    $this;
        }
        function 
    accept(Renderer $renderer) {
            
    parent::accept($renderer);
            foreach (
    $this->children as $child) {
                
    $child->accept($renderer);
            }
        }
    }
    class 
    PageView extends CompositeView {
        function 
    execute(ServiceLocator $locator) {
            return array(
    'username' => $locator->session()->user()->getUsername());
        }
    }
    class 
    WelcomeMessagesView extends View {
        function 
    execute(ServiceLocator $locator) {
            
    // you would obviously use the service locator here
            
    return array(
                array(
    'title' => 'Welcome 1''body' => 'Welcome Body 1'),
                array(
    'title' => 'Welcome 2''body' => 'Welcome Body 2')
            );
        }
    }
    class 
    ForumPostsView extends View {
        function 
    execute(ServiceLocator $locator) {
            return array(
                array(
    'title' => 'Post 1''body' => 'Post Body 1'),
                array(
    'title' => 'Post 2''body' => 'Post Body 2')
            );
        }
    }
    class 
    Renderer {
        protected 
    $locator;
        protected 
    $vars = array();
        function 
    __construct(ServiceLocator $locator) {
            
    $this->locator $locator;
        }
        function 
    visit(View $view) {
            if (
    is_array($vars $view->execute($this->locator))) {
                
    $this->vars[get_class($view)] = $vars;
            }
        }
        function 
    render($template) {
            
    // TODO: extract vars, include template
            
    var_dump($this->vars);
        }
    }

    $factory = new Factory();
    $renderer = new Renderer(new ServiceLocator());
    $factory->views()->homePage()->accept($renderer);
    echo 
    $renderer->render('myPageTemplate'); 

  3. #78
    SitePoint Addict
    Join Date
    Feb 2007
    Posts
    251
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Forgot to answer your other questions.

    As you can see, the page view is created in a factory method. This way you can subclass the factory to create variations on the home page, etc. The factory method would be the place to carry out any changes to the view based on model state, i.e., user type, etc. You could obviously pass the locator to the factory constructor for the purpose of interrogating the model.

  4. #79
    SitePoint Addict
    Join Date
    Feb 2006
    Posts
    281
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Cuberoot,

    Do you think anything wrong with doing:

    PHP Code:
    <?php  
    class ControllerCommonDefault extends Controller {
        function 
    index() {
            
    $this->document->setTitle($this->config->set('store'));
            
            
    $this->data['title'] = $this->config->set('store');
            
            
    $this->id       'content';
            
    $this->template 'common/default.tpl';
            
    $this->layout   'common/layout';
            
    $this->children = array('boxes/navigation');
                    
            
    $this->response->set($this->render());
        }
    }
    ?>

  5. #80
    SitePoint Enthusiast
    Join Date
    Jun 2007
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Big thanks for this great reply cuberoot, I definetely understand the whole idea much better now and it looks really great in my opinion. I will start to implement something like this in my applications now. Thanks again!

  6. #81
    SitePoint Addict
    Join Date
    Feb 2007
    Posts
    251
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @blueyon:

    I don't think there's anything wrong with that approach. It obviously puts less distance between the view and the controller though. What you end up with is what Martin Fowler calls a Passive View or a Supervising Controller, depending on whether or not the templates you include contain any logic.

    http://www.martinfowler.com/eaaDev/PassiveScreen.html
    http://www.martinfowler.com/eaaDev/S...Presenter.html

    @myc:

    You bet. Glad you found it helpful.

  7. #82
    SitePoint Evangelist
    Join Date
    Aug 2005
    Location
    Winnipeg
    Posts
    498
    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.
    CodeIgnitor is probably one of the most tightly coupled MVC frameworks so I wouldn't take them as an example of best practice in MVC.

    Anyways a few things:

    1. Comments in your index.php page. Really nessecary?

    PHP Code:
    // Locator
    $locator =& new Locator(); 
    No kidding. Those comments are redundant when you write self-documenting code and they consume valuble vertical screen space.

    2. Your Locator object is quite specific. Tight coupling ensues.

    createModel() and createView() are not really the interest of a service locator -- IMHO it's more like a generic storage container, similar to a registry but more also a factory.

    I suppose you could have view and model creation hardcoded into the class but I dislike that approach because if you ever used your framework in a CLI environment those methods would be pointless. Looser coupling would allow you to only pick and choose what you need.

    3. Your base model is hardcoded with mysql_* -- I would rather just implement an interface for each model if anything. Otherwise just let users define their own classes, etc. Or use an ORM or similar solution inside your model class.

    4. Why is the Request implemented as a singleton? Honestly, I think that is the most abused pattern of all. Unless your application will break if more than one instance of an object is created why bother? Secondly by nature of the fact that most Request objects work directly with GPC super globals, the object intrinsically acts as a singleton. If you instantiated 3 objects they would all return the same data anyways.

    5. The Request object again. isPost() method really nessecary??? Can you give me an example of when you actually needed to detemrine this state? I had this in my own framework until I reached 30K lines of code in my application and realized I never needed to have knowledge of that. Unless you can give me an example and I can't offer an alternative solution I think this is a classic case of developers over doing it and making things more complex then they need to be.

    6. Response is nice. I like how you handle compression in that object. I'll have to think about that but I might borrow that technique. Although I can also see that functionality going in several other places as well...

    7. I couldn't find anywhere in your code the implementation for handling forwarding instead of redirection?

    Your views are simple, which is good. Almost identical to my own. PHP Alternative syntax all the way, forget Smarty and related libraries unless you have an absolute requirement to use them -- such as allowing end users to modify their templates -- something that PHP templates wouldn't be very good to do.
    The only constant in software is change itself

  8. #83
    Spirit Coder allspiritseve's Avatar
    Join Date
    Dec 2002
    Location
    Ann Arbor, MI (USA)
    Posts
    648
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by PCSpectra View Post
    5. The Request object again. isPost() method really nessecary??? Can you give me an example of when you actually needed to detemrine this state? I had this in my own framework until I reached 30K lines of code in my application and realized I never needed to have knowledge of that. Unless you can give me an example and I can't offer an alternative solution I think this is a classic case of developers over doing it and making things more complex then they need to be.
    PHP Code:
    if ($_POST):
        
    // Handle form submission
    else:
        
    // display form
    endif; 
    I don't know about overdoing it... maybe oversimplifying though.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •