Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Templating system scoping issue

I'm trying to whip up a skeleton View system in PHP, but I can't figure out how to get embedded views to receive their parent's variables. For example:

View Class

class View
{
    private $_vars=array();
    private $_file;

    public function __construct($file)
    {
        $this->_file='views/'.$file.'.php';
    }

    public function set($var, $value=null)
    {
        if (is_array($var))
        {
            $this->_vars=array_merge($var, $this->_vars);
        }
        else
            $this->_vars[$var]=$value;

        return $this;
    }

    public function output()
    {
        if (count($this->_vars))
            extract($this->_vars,  EXTR_REFS);
        require($this->_file);
        exit;
    }

    public static function factory($file)
    {
        return new self($file);
    }
}

test.php (top level view)

<html>
    <body>
        Hey <?=$name?>! This is <?=$adj?>!
        <?=View::factory('embed')->output()?>
    </body>
</html>

embed.php (embedded in test.php

<html>
    <body>
        Hey <?=$name?>! This is an embedded view file!!
    </body>
</html>

Code:

$vars=array(
    'name' => 'ryan',
    'adj' => 'cool'
);
View::factory('test')->set($vars)->output();

Output:

Hey ryan! This is cool! Hey [error for $name not being defined] 
this is an embedded view file!!

The problem is the variables I set in the top level view do not get passed to the embedded view. How could I make that happen?

like image 624
ryeguy Avatar asked Jul 05 '26 07:07

ryeguy


1 Answers

So, I'm not exactly answering your question, but here's my super-simple hand-grown template system. It supports what you're trying to do, although the interface is different.

// Usage
$main = new SimpleTemplate("templating/html.php");
$main->extract($someObject);
$main->extract($someArray);
$main->name = "my name";
$subTemplate = new SimpleTemplate("templating/another.php");
$subTemplate->parent($main);
$main->placeholderForAnotherTemplate = $subTemplate->run();
echo $main; // or $main->run(); 

// html.php
<html><body><h1>Title <?= $name ?></h1><p><?= $placeHolderForAnotherTemplate ?></p></body></html>

    <?php
// SimpleTemplate.php
function object_to_array($object)
{
    $array = array();
    foreach($object as $property => $value)
    {
        $array[$property] = $value;
    }

    return $array;
}

class SimpleTemplate
{
    public $source;
    public $path;
    public $result;
    public $parent;

    public function SimpleTemplate($path=false, $source=false)
    {
        $this->source = array();
        $this->extract($source);
        $this->path($path);
    }

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

    public function extract($source)
    {
        if ($source)
        {
            foreach ($source as $property => $value)
            {
                $this->source[$property] = $value;
            }
        }
    }

    public function parent($parent)
    {
        $this->parent = $parent;
    }

    public function path($path)
    {
        $this->path = $path;
    }

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

    public function __get($name)
    {
        return isset($this->source[$name]) ? $this->source[$name] : "";
    }

    public function mergeSource()
    {
        if (isset($this->parent))
            return array_merge($this->parent->mergeSource(), $this->source);
        else
            return $this->source;
    }

    public function run()
    {
        ob_start();
        extract ($this->mergeSource());
        include $this->path;
        $this->result = ob_get_contents();
        ob_end_clean();
        return $this->result;
    }
}
like image 184
Sean Clark Hess Avatar answered Jul 06 '26 21:07

Sean Clark Hess