views:

1982

answers:

4

I have quite a lot of PHP view files, which I used to include in my controllers using simple include statements. They all use methods declared in a view class which they get like $view->method(); However I recently decided that it would be better if the including would also be done by this view class. This however changes the scope of the included file so that $view is no longer defined. Here is a code example:

in someViewFile.php (BOTH siuations)
    <html>
    <head><title><?php echo $view->getAppTitle(); ?></title>
    etc.
OLD SITUATION in controller:
    $view = new view;
    include('someViewFile.php'); //$view is defined in someViewFile.php
NEW SITUATION in controller:
    $view = new view;
    $view->show('someViewFile'); //$view is not defined in someViewFile.php

Right now I hacked my way around the problem using this in the view class:

public function show($file){
    $view = &$this;
    include($file.".php");
}

Is there anyway to declare the scope of the inluded file or is this the best way of solving the problem?

These examples are off coarse simplified.

A: 

to me this looks like a strangely reversed use of the 'view'. instead of preparing stuff in your controler and sending it to the viewfile which is then displayed, you display the controller and embed some view bits in it... that's not really separation of code and view anyways so I would suggest to solve the whole thing differently by not including the few files but by displaying the view files and drafting the necessary dynamic content from the controller.

tharkun
Yeah, your right, I use MVC names but I don't really use MVC, my way is more like: Data_abstraction-Template-Do_stuff_with_data_and_user_supplied_data_script (D-T-D?)
Pim Jager
+1  A: 

You can't change include() scope, no, so your method is probably about as good as it gets in the situation you're describing. Though I'd skip the ugly PHP4-compat ampersand, myself.

chaos
+3  A: 

Here' a simplified but functional view class that I've seen around quite a lot and use quite a lot.
As you can see in the code below: you instantiate a view with the filename of the template file.
The client code, probably a controller, can send data into the view. This data can be of any type you need even other views.
Nested views will be automatically rendered when the parent is rendered.
Hope this helps.

// simple view class
class View {
    protected $filname;
    protected $data;

    function __construct( $filename ) {
        $this->filename = $filename;
    }

    function escape( $str ) {
        return htmlspecialchars( $str ); //for example
    }

    function __get( $name ) {
        if( isset( $this->data[$name] ) {
            return $this->data[$name];
        }
        return false;
    }

    function __set( $name, $value ) {
        $this->data[$name] = $value;
    }

    function render( $print = true ) {
        ob_start();
        include( $this->filname );
        $rendered = ob_get_clean();
        if( $print ) {
            echo $rendered;
            return;
        }
        return $rendered;
    }

    function __toString() {
        return $this->render();
    }
}

Usage

// usage
$view = new View( 'template.phtml' );
$view->title = 'My Title';
$view->text = 'Some text';

$nav = new View( 'nav.phtml' );
$nav->links = array( 'http://www.google.com' => 'Google', 'http://www.yahoo.com' => 'Yahoo' );

$view->nav = $nav;

echo $view;

The templates

//template.phtml
<html>
    <head>
        <title><?php echo $this->title ?></title>
    </head>
    <body>
        <?php echo $this->nav ?>
        <?php echo $this->escape( $this->text ) ?>
    </body>
</html>

//nav.phtml
<?php foreach( $this->links as $url => $link ): ?>
    <a href="<?php echo $url ?>"><?php echo $link ?></a> 
<?php endforeach ?>
meouw
I think there's a tiny typo where it says "filname" ?
Noio
A: 

What i do, ( i don't know how OK it is) is simply

extract($GLOBALS);
include $view.".php";

Sure as hell works

Cheers!

droope