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
Extending View class not ideal
  • The View class is not well suited to be extended. Many of the methods explicitly call the "View" class directly, as opposed to using "self", which means that you are forced to reimplement methods that should not have to be reimplemented. The "View::factory()" method is a typical example:

    public static function factory($file = NULL, array $data = NULL)
    {
      return new View($file, $data);
    }
    

    You would have to reimplement it only to change the class name of the object that is returned, i.e. return new View would have to be changed to something like return new View_Template, which should not be necessary.

    Was the class written like this on purpose, or is it just something that no one has noticed/is bothered by?

  • View class (which is an empty class) extends Kohana_View if I'm not mistaken. You can just override it by using the CFS.

    application/classes/view/template.php

    class View_Template extends Kohana_View {}

    application/classes/view.php

    class View extends View_Template {}

    This way, return new View()... refers to View_Template.

  • Yeah, I mixed up View and Kohana_View, but the problem is still there. Excerpt from SYSPATH/classes/kohana/view.php:

    class Kohana_View {
      ...
      public static function factory($file = NULL, array $data = NULL)
      {
        return new View($file, $data);
      }
      ...
    }
    

    If I extend Kohana_View I will have to reimplement "factory" (and most of the methods in the class) and change the class of the object that is returned. Now, if the return statement read something like this:

        return new self($file, $data);
    

    Or:

        $class = __CLASS__;
        return new $class($file, $data);
    

    ... and if static variables would be assigned using self::$var_name instead of View::$var_name -- then the Kohana_View class would be extendable.

  • As with most kohana classes its designed so that you extend Kohana_View with one or more classes that ultimately finish up with a customised class still called View.

    It would only be possible to do something long the lines you're suggesting (not quite what you have) if you used late static binding, which requires php 5.3 and 3.0 - 3.2 are designed to support php 5.2 as well.

  • In kohana, the way it works by calling View::some_function it's equivalent static::some_function because there is never anything above View in the hirarchy since you're implementation goes bellow, as far as the class hirarchy is concerned. eg. current: View < Kohana_View, extended: View < My_Stuff < Kohana_View, etc.

    I don't see the point here. Even in the example, if it was new self then it would return the Kohana_View and not the extention. Because it calls new View it's always returning the extention.

  • I think I am being misunderstood, or maybe I am misunderstanding something here.

    The Kohana_View class has all the functionality that I need. The only thing I want to do is modify the static capture() method so that it throws the parsed PHP through one last method, which I have defined myself, before sending it back:

    class Template extends Kohana_View {
    
      public static function capture($kohana_view_filename, array $kohana_view_data)
      {
        $captured = parent::capture($kohana_view_filename, $kohana_view_data);
    
        return self::parse_tpl($captured, $kohana_view_data);
      }
    
      public static function parse_tpl($template, $data)
      {
        // parse $template using the $data array here
    
        return $result;
      }
    
    }
    

    Now, if I do something like $menu = Template::factory('components/menu', $menu); then I will get an instance of View back. If I call Template::set_global('page_title', '...')then the global variable will be saved in View::$_global_data because that is what the View class does (it saves it like this: View::$_global_data[$key] = $value;). If the global variable were saved like self::$_global_data[$key] = $value; then the data would be saved in the class that calls the method (in this case Template).

    If I just redefine the factory() method then I can piggyback on the View class (storing global variables and stuff like that in the View class as opposed to in the Template class) but that is not what I want to do. When I save a global variable I want it to be stored in Template::$_global_data and not in View::$_global_data.

    Now, I could just copy and paste the Kohana_View class, rename it and forget about extending anything, but I do not see why I should do that. I want to reuse the Kohana_View code so that I do not have to rewrite code that already has been written.

  • Yes, but in kohana you do that by adding a class in application/classes/view.php

    Class View extends Kohana_View
    {
        // exactly as per your existing definition of Template class
    }
    

    And then you get the inheritance and your new code within the View class.

    Or is it that you want to use Template and the existing View together in the same app? If so, you would need to either change the factory methods etc as you say, or do it with the single view class and add a parse_template flag to the class so that the controller can specify whether or not to use your code.

    The issue is that the self keyword in php will always refer to the class the currently executing code is defined in regardless of the called class. To implement something as you have above you would need the static keyword and get_called_class function - see http://php.net/manual/en/language.oop5.late-static-bindings.php for more.

    However, those are only available in php 5.3 and KO3.0-3.2 supports php 5.2 so therefore that approach can't be used in core at this point. I think 3.3 will require 5.3 which would allow more options but I'm not sure if that decision has been taken.

  • Thank you guys, I get it.

    What I wanted to do was have a Template class which derives all its functionality from Kohana_View, but with one difference: In addition to the normal capturing of a file, through capture(), it would also parse a lightweight templating language (a simple {var_name} and {iterable}...{/iterable} language):

    <ul>
      <li>Disclaimer: <?php echo $disclaimer ?></li>
    {colors}
      <li>{item} is #{hex}</li>
    {/colors}
    </ul>
    

    Because it extends Kohana_View the Template class would be an instance of it and thus, this would work:

    $items = array(
      'disclaimer' => 'Colors are very colorful!'
      'colors' => array(
        array('item'=>'Red', 'hex'=>'FF0000'),
        array('item'=>'Green', 'hex'=>'00CC00'),
        array('item'=>'Blue', 'hex'=>'0033CC'),
      ),
    );
    $menu = Template::factory('components/menu', $items);
    $this->response->body($menu);
    

    The Template inherits the __toString() magic method from Kohana_View (as well as all the other useful View methods and functionality). If we look at Kohana_Response::body() then we see that it would be treated just like a normal Kohana_View, which is to say that it would be cast to string:

    public function body($content = NULL) {
      ...
      $this->_body = (string) $content;
      ...
    }
    

    In other words, the idea was to modify Kohana_View so that it also uses a lightweight templating language, but I wanted to do it as transparently as possible. By simply piping the captured file through an extra method, parsing the template, before returning it you leave the Kohana_View API untouched, which is as transparent as you can get. The class would be called Template in order to avoid the overhead if you do not want to use the templating language (although you could name it View if you always use it).

  • @Sverri To be honest, given the functionality that you're actually looking for, you may as well bite the bullet and use Kostache instead. The template syntax (mustache) is similar to yours, and you get to work properly with view models that will solve all your issues and move all of that view logic out of the controllers.

    https://github.com/zombor/kostache

  • @zeebee I was really just thinking about this as an exercise. I did jot down a working parser, if you want to call it that. It basically just searches and replaces single {var_name} variables and expands {iterable}...{/iterable} loops. The loops are expanded first, starting from the inner-most array, and then the variables are replaced, which avoids array key naming conflicts.

    The entire shebang could easily fit into a function call but I decided to break it up a little and made a class for it. Give it a look see, if you are interested:

    http://kohana.pastebin.com/PZL36Bty

    I will take a look at KOstache, though. Thanks.

Howdy, Stranger!

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

In this Discussion