bamboo
=========================================

Bamboo is a PHP template engine, which has the following characteristics: 
- native PHP as template language; no compile. familiar and well-defined syntax
- using global functions as helpers/escapers; no redundant `$e->h()`/`E::h()`. just `eh()`
- facility to _PULL_ template variables from the program side


Installation
------------------------------------------

```sh
composer install tyam\bamboo
```


Basic Usage
--------------------------------------------

PHP side
```php
// You must specify template base directory to the bamboo engine.
$basedirs = ['/your/template/dirs', '/come/here'];
$engine = new \tyam\bamboo\Engine($basedirs);

// Render the template with template variables. You get an output string.
$variables = ['title' => $this->getTitle(), 'content' => $this->getContent()];
$output = $engine->render('mytpl', $variables);
$respond->setOutput($output);
```

template side: /your/template/dirs/mytpl.php
```php
<?php /* You must escape string explicitly. */ ?>
<?= htmlspecialchars($title) ?> 
<div>
<?= $content ?>
</div>
```

- A filename extension for template file is 'php'
- Path separator for the base directory is fixed as slash. bamboo engine converts to host specific one.


Including another template
------------------------------------------

subject template: /your/template/dirs/mytpl.php
```php
content comes here...
<?php $renderer->include('common/another'); ?>
your content continues...
```

another template: /your/template/dirs/common/another.php
```php
write anything...
```

- `$renderer` is a special variable from bamboo, which provides you the rendering instructions.
- Template files can be grouped by subdirectories. Then a template name becomes 'subdir/template' (slash delimited).


Template inheritance
------------------------------------------

child template: /your/template/dirs/content.php
```php
<?php $renderer->wrap('common/layout') ?>
content comes here...
```

parent template: /your/template/dirs/common/layout.php
```php
<html>
<body>
header...
<div class="main">
<?php $renderer->content(); ?>
</div>
footer...
</body>
</html>
```

- In child template, by `wrap()` you can specify parent template. The rest part becomes a content for the parent.
- In parent template, by `content()` you can outpupt the content generated by a child.
- Template inheritance must be _single_. You cannot specify `wrap()` twice.
- Multi-level inheritance is supported. Note that `content()` outputs a result of _exact_ child template. You must call `content()` every parent template.


Sections (Capturing block for other template)
----------------------------------------------------

child template: /your/template/dirs/content.php
```php
<?php $renderer->wrap('common/layout'); ?>
<?php $renderer->section('title') ?>
<?= htmlspecialchars($title) ?>
<?php $renderer->endsection('title') ?>
content comes here...
```

parent template: /your/template/dirs/common/layout.php
```php
<html>
<head>
<title><?php $renderer->yield('title') ?></title>
</head>
...
```

- You can capture a block of content, called 'section', between `section()` and `endsection()`.
- Sections are named. Then, you can specify a name of a section to `yield()` to output a block.
- Passing a section name to `endsection()` is redundant and optional, but useful as sanity check purpose. Bamboo throws an exception when the passed name was insane.
- Note that evaluation order is matter. Bamboo always evaluates child first. So you can `yield()` only sections captured by descendant templates.


Variables passing
------------------------------------------------

```php
<?php $renderer->wrap('parent', ['title' => $title]) ?>
<?php $renderer->include('another', ['title' => $title]) ?>
```

- You can pass template variables when you call another template.
- Note that you must pass template variables for each template. Template variables are not shared among templates.


Variables pulling
--------------------------------------------------

On production sites, a page is filled by dynamic contents. User name, logged in or not, notifications, recommendations, advertisements, etc. They all are side contents, not a main content.  
We must fetch them all from the Model layer, then bind to template as variables. That code makes our PHP side (controller, responder or anything) ugly.

To improve this situation, bamboo has the variable-pulling facility. With it, templates automatically pull template variables from PHP side. Then, you can separate the code of side contents from that of main content.  
Variable-pulling is actualized by passing a variable provider to bamboo engine.

PHP side
```php
use tyam\bamboo\Engine;
use tyam\bamboo\VariableProvider;

class MyController implements VariableProvider
{
    // This is the method declared abstract in VariableProvider and providing side contents.
    public function provideVariables(string $template): array
    {
        // Here you provide side contents.
        return [
            'user' => $this->getUser(), 
            'notifications' => $this->getNotifications(), 
            'recommendations' => $this->getRecommendations()
        ];
    }

    public function action()
    {
        // Get domain result in some way.
        $result = $this->callDomain();

        // Pass $this as VariableProvider to bamboo engine.
        $engine = new Engine(self::$basedirs, $this);

        // Just bind domain result to the template.
        $output = $engine->render('my/template', ['result' => $result]);

        // Then output. Thanks to variable-pulling, the code is quite straight forward.
        $this->response->output($output);
    }
}
```

- Before rendering a template, bamboo calls `provideVariables()` with its name. Then, you return variables for the template.
- In above example, template varialbes `user`, `notifications` and `recommendations` can be used in 'my/template', its parents and all included templates.
- If variable names collided, explicit ones, which is passed via `$engine->render()`, `$renderer->wrap()` or `$renderer->include()`, hides implicit ones, which is pulled via `provideVariables()`.


Getting section values
----------------------------------------------

As a effect of template rendering, other than returned output, there exists section values.  
Usually section values are consumed in templates, and PHP side has no interest in them.  
But, when PHP side is requiring something other than body output, sections are good place to track.  
You can pass an `ArrayAccess` object to `$engine->render()`. Then bamboo uses this array to hold all section values, and you can investigate it after rendering.

The good example is e-mail tamplating.

template: e-mail template
```php
<?php /* Store Subject header in a section */ ?>
<?php $renderer->section('Subject') ?>
Confirmation instructions
<?php $renderer->endsection() ?>

<?php /* Store To header in a section */ ?>
<?php $renderer->section('To') ?>
<?= $user->getEmail() ?>
<?php $renderer->endsection() ?>

Thanks for signing up!
To get started, click the link below and confirm your account.
<?= $confirmationUrl ?>
```

PHP side
```php
$variables = ['user' => $user, 'confirmationUrl' => $confirmationUrl];

// Pass an empty array for sections. 
$sections = new \ArrayObject();
$output = $engine->render('email/signup-confirm', $variables, $sections);

// Now we get Subject header and To header from sections
$mailer->setSubject($sections['Subject']);
$mailer->setTo($sections['To']);

$mailer->setBody($output);
$mailer->send();
```

In the example above, we use sections to track some e-mail header values.


Other topics
-----------------------------------------------

- I recommend you define helper/escaper functions in the global namespace. If that is a bother, you can find some functions in 'function.php' in this package. Call `Engine::loadFunctions()` if you like it.


Lisence
-----------------------------------------------

Bamboo is MIT licensed. See [LICENSE](LICENSE).
