TIP: Use Markdown or, <pre> for multi line code blocks / <code> for inline code.
These forums are read-only and for archival purposes only!
Please join our new forums at discourse.kohanaframework.org
KO3 Request Chain Example
  • I've been digging into the K03 beta with glee and have discovered that requests are chain-able.

    I'm not sure if this is exactly how Shadowhand intends things to be done but the following example works.

    // Here is a test controller
    class Controller_Test extends Controller 
    {
    
        // Here is my default controller action
        public function action_index()
        {
            // Create a base view
            $view = View::factory('theme');
    
            // Assign another view to the variable menu in the base view
            $view->menu = View::factory('menu');
    
            // Create a new Kohana request and execute !
            // Here I am executing the default action from Controller_Welcome
            $welcome = Request::factory('welcome')->execute();
    
            // Assign the response from Controller_Welcome to the **content** variable
            // in my base view
            $view->content = $welcome->response;
    
            // Assign another variable just with a string
            $view->footer = 'this is my footer';        
    
            // Render the view.
            echo $view->render();
        }
    }
    

    Hopefully Shadowhand will correct me if I'm not using the Request factory as intended.

  • That is almost exactly how it is done, except that your last line should read:

    $this->request->response = $view->render();
    
  • sweet.

    Excellent work.

  • Here's another working example. KO3 Template/Theme/Website Controller

    class Controller_Website extends Controller 
    {
        public $template = NULL;  // you could set a default view
        public $auto_render = TRUE;
    
        public function before()
        {
            if( ! Request::$is_ajax && $this->template ){
                $this->template = View::factory($this->template);
            } 
        }
    
        public function after()
        {
            if( ! Request::$is_ajax && $this->auto_render && $this->template ) {
                $this->request->response = $this->template;
            }       
        }
    
    }
    

    Controller extending the Website Controller

    class Controller_Welcome extends Controller_Website  {
    
            public $template = 'theme';   // template view
    
        public function action_index()
        {
            $this->template->menu = Request::factory('menu')->execute()->response;
            $this->template->content = View::factory('welcome');
            $this->template->footer = Request::factory('footer')->execute()->response;
        }
    
    } // End Welcome
    

    again. only pulled together by reading the code comments so there could be a better way to do it

  • There is already a Controller_Template that ships with KO3.

  • thanks. i must be blind. Glad to at least see that my attempt was on the money.

  • Wow, KO3 is damn cool.

    class Controller_Welcome extends Controller {

    public function action_test()
    {
    $this->request->response = Request::factory('welcome/xxx')->execute()->response;
    }

    public function action_xxx()
    {
    $this->request->response = View::factory('v_welcome')->render();
    }
    } // End Welcome
  • The HMVC functionality looks very promising.

    If all of your controllers extend the new Controller_Template, do you need to specifically call parent::before() or parent::after() if you plan to override those methods in any of your child controllers?

    Also, what is the suggested way to simulate the 2.x $auto_render = FALSE functionality? Should we override the after() method and set $this->request->response = NULL ?

  • You should always call parent:: methods if they exist.

    Overload the after() method if you don't automatically want to add the response. I should probably add the $auto_render to the template controller though.

  • I am having trouble wrapping my head around this.

    I have extended Controller_Template with my own barebones default template. I have a Controller called Contacts:

    [code]
    class Controller_Contacts extends Controller_Default {
    public function action_index() {
    $get_contacts = new Model_Contacts();
    $contacts = $get_contacts->get_contacts();
    return $contacts;
    }
    }
    [/code]

    In my base controller, I am attempting to request Contacts and then output the result to a view.

    [code]
    class Controller_Home extends Controller_Default {
    public function action_index() {
    $contacts = Request::factory('contacts')->execute()->response;
    $this->template->contacts = View::factory('contacts', $contacts)->render();
    }
    }
    [/code]

    I get this error however:

    [quote]
    ErrorException [ Recoverable Error ]: Argument 2 passed to Kohana_View::factory() must be an array, object given...
    [/quote]

    What am I doing wrong?
  • Sigh, I have no idea what the codes are to format the above...
  • <code> instead of square brackets [code]

    And if I'm not mistaken, the line:

    return $contacts;

    will not return the intended result (collection of contacts) because the return value will not be sent to response. What you will get instead is a view object that was causing the error.
  • Request::factory('contacts')->execute()->response is not an array, which is expected as second argument in View::factory().

    class Controller_Home extends Controller_Default {
    public function action_index() {
    $contacts = Request::factory('contacts')->execute()->response;
    $this->template->contacts = View::factory('contacts', array('content' => $contacts))->render();
    // OR
    $this->template->contacts = View::factory('contacts')->set('content', $contacts)->render();
    }
    }

  • Thanks for the help. I'm still having problems however. I've changed my structure a little and now have the below. I have no error messages, but the echo results from $contacts in the Contacts View outputs all the variables in my Default Controller. To be honest, I have absolutely no clue why that is and makes very little sense to me.

    Results of page:

    View Object ( [_file:protected] => /home/myuser/bin/kohana/newApp/views/templates/default.php [_data:protected] => Array (
    [title] => Blah Blah [meta_keywords] => my, keywords, separated [meta_description] => my description
    [meta_copywrite] => 12/10/2010 [header] => [content] => [footer] =>
    [styles] => Array (
    [http://www.somewhere.org/css/screen.css] => screen [http://www.somewhere.org/css/print.css] => print
    [http://www.somewhere.org/css/ie.css] => ie [http://www.somewhere.org/css/style.css] => style )
    [scripts] => Array ( [0] => http://www.somewhere.org/js/jquery-1.4.4.min ) ) )


    Home Controller:

    class Controller_Home extends Controller_Default {
    public function action_index() {
    $set_views = array();
    $contacts = Request::factory('contacts')->execute()->response;
    $set_views['contacts'] = View::factory('contacts')->set('contacts', $contacts)->render();
    $this->template->content = View::factory('index', $set_views);
    }
    }


    Default Controller:

    class Controller_Default extends Controller_Template {
    public $template = 'templates/default';
    public function before() {
    parent::before();
    if($this->auto_render) {
    $this->template->title = 'Blah Blah';
    $this->template->meta_keywords = 'my, keywords, separated';
    $this->template->meta_description = 'my description';
    $this->template->meta_copywrite = '12/10/2010';
    $this->template->header = '';
    $this->template->content = '';
    $this->template->footer = '';
    $this->template->styles = array();
    $this->template->scripts = array();
    }
    }
    public function after() {
    if($this->auto_render) {
    $styles = array(
    url::base() . 'css/style.css' => 'style',
    url::base() . 'css/ie.css' => 'ie',
    url::base() . 'css/print.css' => 'print',
    url::base() . 'css/screen.css' => 'screen',
    );
    $scripts = array(url::base() . 'js/jquery-1.4.4.min');
    $this->template->styles = array_reverse(array_merge($this->template->styles, $styles));
    $this->template->scripts = array_reverse(array_merge($this->template->scripts, $scripts));
    }
    parent::after();
    }
    }


    Contacts Controller:

    class Controller_Contacts extends Controller_Default {
    public function action_index() {
    $get_contacts = new Model_Contacts();
    $contacts = $get_contacts->get_contacts();
    return $contacts;
    }
    }


    Contacts Model:

    class Model_Contacts extends Model {
    public function __construct() {
    parent::__construct();
    }

    public function get_contacts() {
    $query = DB::select()->from('contact');
    return $query->execute('port');
    }
    }


    Contacts View:

    <?php
    print_r($contacts);
    ?>


    Index View:

    <?php
    echo $contacts;
    ?>


    Default View:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
    <html xmlns="http://www.w3.org/1999/xhtml&quot; xml:lang="en" lang="en">
    <head>
    <meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
    <meta http-equiv="Content-Language" content="en-us" />
    <title><?php echo $title;?></title>
    <meta name="keywords" content="<?php echo $meta_keywords;?>" />
    <meta name="description" content="<?php echo $meta_description;?>" />
    <meta name="copyright" content="<?php echo $meta_copywrite;?>" />
    <?php foreach($styles as $file => $type) { echo HTML::style($file, array('media' => $type)), "\n"; }?>
    <?php foreach($scripts as $file) { echo HTML::script($file, NULL, TRUE), "\n"; }?>
    </head>
    <body>
    <div id="container">
    <?php echo $header;?>
    <?php echo $content;?>
    <?php echo $footer;?>
    </div>
    </body>
    </html>
  • class Controller_Contacts extends Controller_Default {
    public function action_index() {
    $get_contacts = new Model_Contacts();
    $contacts = $get_contacts->get_contacts();
    $this->request->response = $contacts;
    }
    }
  • Wow, I feel like such a noob, and although I am, it feels especially more so now.

    Thanks, now.. I understand a little more. :-D
  • But lets be clear that you would never set your response this way. A response should be HTML, or JSON, or some other standard output type. This entire thread is a total abuse of the HMVC system.
  • Shadowhand, I don't follow. My understanding of OOP is to create a class for each object, and then manipulate the object instances through defined methods, which I am doing so through the Home class. Is this incorrect thinking with regards to MVC programming?

    If I want to build a site and each distinct object in that site is its own class, is my above thinking the right way to go about it or is there another more appropriate way?
  • The main issue is that subrequests should return some form of text based content. Eg if you need to use HMVC at all your Controller_Contacts should be returning the rendered contacts view, not an array of models to be rendered by the parent controller. As your parent controller is harcoded to use the contacts data, you could (in the example you post) do away with the contacts controller altogether and (in a single request) get the contacts models and render them in Controller_Home.

    Other things to look at is that there is no need for Model_Contacts::get_contacts to be an instance method as it is not related to a single contact model. It would be cleaner to have it a static method which would allow you to do:

    class Controller_Home {
    public function action_index() {
    $contacts = Model_Contacts::get_contacts();
    $this->template->content = View::factory('contacts')
    ->set('contacts',$contacts);
    }
    }


    Also, get_contacts as a method name doesn't indicate which contacts its getting - maybe fetch_all or find_all would be better.
  • I eventually intend to use the controllers to process more data, add functionality, etc. Get_contacts makes more sense when you see that one of the functions is get_contact for a specific contact.

    As per your first point, I get it. It does make more sense for the Contacts controller to do its thing, and that includes processing any associated view.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion