Git Product home page Git Product logo

php-micro-template's Introduction

Latest Version Maintainability Build Status Coverage Status MIT License

php-micro-template

A minimalistic, lightweight templating engine for PHP based on regular expressions.

Features

  • Replace variables inside a template
  • Iterate over an array or iterable object
  • Conditional sections
  • Pass objects
  • call functions

Requirements

  • Requires at least PHP 7.1

Installation

The recommended way to install php-micro-template is through Composer:

$ composer require wol-soft/php-micro-template

Examples

First create your template file:

<html>
    <h1>{{ pageTitle }}</h1>

    <ul class="row">
        {% foreach products as product %}
            {% if product.isVisible() %}
                <li class="product">
                    <span>{{ productHead }}</span>
                    <span>{{ product.getTitle() }}</span>
                </li>
            {% endif %}
        {% endforeach %}
    </ul>

    {% if showVersion %}
        <div class="version">1.0.1</div>
    {% endif %}
</html>

Afterwards create a new instance of the Render class and render your template:

<?php

use PHPMicroTemplate\Render;

/* ... */

$render = new Render(__DIR__ . '/Templates/');

$result = $render->renderTemplate(
    'productList.template',
    [
        'pageTitle' => $translator->translate('availableProducts'),
        'productHead' => $translator->translate('product'),
        'products' => $products,
        'showVersion' => true
    ]
);

/* ... */

Instead of saving your templates into files you can also prepare a string which contains the template:

<?php

use PHPMicroTemplate\Render;

/* ... */

$myPartialTemplate = '
    {% foreach products as product %}
        {% if product.isVisible() %}
            <li class="product">
                <span>{{ productHead }}</span>
                <span>{{ product.getTitle() }}</span>
            </li>
        {% endif %}
    {% endforeach %}
';

$render = new Render();

$result = $render->renderTemplateString(
    $myPartialTemplate,
    [
        'productHead' => $translator->translate('product'),
        'products' => $products
    ]
);

/* ... */

Replacement of variables

Values which are assigned to the template and used directly will be casted to string. For assigned objects you can call methods which return a value. Afterwards the returned value will be casted to string. As constant values integer numbers, strings in single quotes and booleans (true, false) are supported.

{{ simpleValue }}
{{ myObject.getProperty() }}
{{ 'Hello World' }}
{{ 12345 }}

Your provided data may be a nested array which can be resolved in the template:

$render->renderTemplateString(
    '{{ render.productRender.renderProductName(product.details.name) }}',
    [
        'product' => [
            'details' => [
                'name' => 'MyProduct',
            ],
        ],
        'render' => [
            'productRender' => new ProductRender(),
        ]
    ]
);

Also, public properties of objects may be accessed from the template:

$person = new stdClass();
$person->name = 'Hans';

$render->renderTemplateString(
    '{{ person.name }}',
    [
        'person' => $person,
    ]
);

By default, a used variable which is not provided will result in an UndefinedSymbolException. You can register a callback function via onResolveError to handle unresolved variable errors. The callback function must implement the signature function (string $unresolvedVariable): string. The provided $unresolvedVariable will contain the whole expression which failed to resolve (eg. myUnresolvedVariable, myUnresolvedObject.render(var1, var2)).

$render->onResolveError(function (string $var): string {
    return 'Undefined';
});

// will result in "Person name: Undefined"
$result = $render->renderTemplateString('Person name: {{ name }}');

Loops

If you assign an array or an iterable object you can use the foreach loop to iterate.

{% foreach products as product %}
    <span>{{ product.getTitle() }}</span>
{% endforeach %}

All variables of the parent scope are available inside the loop as well as the current item of the loop. Multiple foreach loops can be nested (compare tests). You can also provide a function which returns an array or an iterable object:

{% foreach product.getIngredients() as ingredient %}
    <span>{{ ingredient.getTitle() }}</span>
{% endforeach %}

Loops support the usage of key value pairs:

{% foreach products as bestSellerNumber, product %}
    <b>Bestseller Nr. {{ bestSellerNumber }}:</b>{{ product.getTitle() }}<br/>
{% endforeach %}

Conditional sections

With the if statement you can create conditional sections. As a condition you can pass either a value which will be casted to bool or call a method on an object. In this case the return value of the function will be casted to bool. Neither multiple values in a single condition combined by operators nor calculations or similar additional functions are provided. For advanced conditions compare the section function calls with a ViewHelper-Object.

{% if showProducts %}
    {% if product.isVisible() %}
        <span>{{ product.getTitle() }}</span>
    {% else %}
        <span>Product {{ product.getTitle() }} currently not available</span>
    {% endif %}
{% endif %}

Multiple if statements can be nested. To invert an if condition the keyword not can be used:

{% if not product.isVisible() %}
    <span>Product {{ product.getTitle() }} currently not available</span>
{% endif %}

function calls

The methods which are called can take parameters. Allowed parameters are variables taken out of the current scope or another function call on an object available in the current scope as well as the supported constant values integer numbers, strings in single quotes and booleans (true, false). As an example a ViewHelper-Object can be assigned to the render process and methods of the ViewHelper can be used in the template for advanced logic inside the template.

<?php

use PHPMicroTemplate\Render;

/* ... */

class ViewHelper
{
    public function count(iterable $list): int
    {
        return count($list);
    }

    public function sum(float ...$values): float
    {
        return array_sum($values);
    }

    public function weight(string $label, int $weight = 400): string
    {
        return sprintf('<span style="font-weight: %d;">%s</span>', $weight, $label);
    }
}

/* ... */

$render = new Render(__DIR__ . '/Templates/');

$result = $render->renderTemplate(
    'functionExample.template',
    [
        'viewHelper' => new ViewHelper(),
        'currencyFormatter' => new CurrencyFormatter(),
        'basePrice' => 3.00,
        'products' => $products
    ]
);

/* ... */
<html>
    <p>Products: {{ viewHelper.count(products) }}
    <ul class="row">
        {% foreach products as product %}
            <li class="product">
                <span>{{ viewHelper.weightFont(product.getTitle(), 600) }}</span>
                <span>Price: {{
                    currencyFormatter.format(
                        viewHelper.sum(
                            product.getPrice(),
                            basePrice
                        )
                    )
                }}</span>
            </li>
        {% endforeach %}
    </ul>
</html>

Additionally, PHP global functions can be used directly in the template as well as assigned callback methods:

<?php

use PHPMicroTemplate\Render;

/* ... */

$render = new Render(__DIR__ . '/Templates/');

$result = $render->renderTemplate(
    'functionExample.template',
    [
        'customCallback' => function(string $in): string {
            return trim(strtoupper($in));
        },
    ]
);

/* ... */
<html>
    <p>{{ customCallback('products') }}</p>
    <span>{{ strtolower('UNDER CONSTRUCTION') }}</span>
</html>

Whitespace tolerance

The templating syntax is whitespace tolerant so a template like the one below would be perfectly fine:

{%if
    product.getCategories()
%}
    <p>Categories:</p>
    <ul>
    {%foreach
         product.getCategories()
            as
         category
    %}
        <li>{{product.getTitle()} [{{   category   }}]</li>
    {%endforeach%}
    </ul>
{%endif%}

php-micro-template's People

Contributors

wol-soft avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

leikodmitry h3rb

php-micro-template's Issues

dotted notation to access variables?

Hello,

Does it possible to use dotted notation to access variables? It looks that doesn't works for me...

$data = [
  'ticket' => [
     'id' => 14,
     'title' => test
  ]
];
$pattern = ' wo-{{ticket.id}}';
echo $render->renderTemplateString($pattern, $data);

Thank you

Use function without class?

Does it possible to use function without embed them into a class ?

I mean for example:

class Formatters {
   public static function dummy() {
       return 'hello world';
   }
}
     ...
        $template = "{{dummy()}}F{{date.format('Ymd')}}-{{sequence.format(8)}}";
        $result = $render->renderTemplateString(
            $template,
            [
               'date' => new DateFormatter,
               'sequence' => new SequenceFormatter,
               'dummy' => Formatters::dummy,
            ]
      ...

image

function with parameters issue...

Hello,

I'm using functions with your template renderer, but I've got an issue with parameters.
I'm unable to pass string or number as parameter directly

image

 $template = "F{{format.date('Y')}}-{{format.sequence(8)}}";
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;

use PHPMicroTemplate\Render;
use Carbon\Carbon;

class TemplateFormat {

   public function sequence($digits=6) {
      return sprintf('%0'.$digits.'d', 7);
   }

   public function date($format='Y') {
      return Carbon::now()->format($format);
   }

}

class Template extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'template:render';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'replace variable into template';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {

        $render = new Render();
        $template = "F{{format.date('Y')}}-{{format.sequence(8)}}";

        $result = $render->renderTemplateString(
            $template,
            [
               'format' => new TemplateFormat,
            ]
        );

        echo  $result . PHP_EOL;
        return Command::SUCCESS;
   }   
}

Any idea what I'm doing wrong?

Regards

Missing important thing in examples

You should add use PHPMicroTemplate\Render to your example cuz people don't know the name of namespace where Render is located (they going to look into src/Render.php file to determine this).

Template Syntax checker

Hello,

It would be nice to have some method to check syntax of the template.
I use your engine with Laravel/Nova application and I would like to have a validation function to check syntax before store it. into database.

I got stupid issues with foreach because I was trying to use PHP syntax instead of the correct one.

Thank you

custom start and end marker

thank you for this library, one thing i need to be able to customize the markers {% %} and the {{ }}
i was trying to replicate a template engine which uses $( and ) as start and end markers for variables, conditional and loop I dont want to edit the library but if its the case then theres no other choice

Error on missing object property

Hello!

If I assign an object (e.g. a Laravel Eloquent model) as a variable and in the template I reference to a non-existent property of the object, the renderer throws an error instead of the UndefinedSymbolException, so I don't know, which property is missing.

TypeError(code: 0): array_key_exists(): Argument # 2 ($array) must be of type array, App\Models\Product given at /var/www/vendor/wol-soft/php-micro-template/src/Render.php:243

Thank You

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.