Installation

You can simple install it by composer, require PHP 5.3 or higher:

composer require undercloud/ant

Usage

Setup

First step - initialize and setup engine:

require 'vendor/autoload.php';

use Ant\Ant;

//setup instance
Ant::init()
	->setup([
		/* define root directory of your templates */
	 	'view'  => '/path/to/view',
		/* define cache directory for compiled templates */
		'cache' => '/path/to/cache',
		/* define logic path, default empty */
		'logic' => '/path/to/logic',
		/* you can define your own template extension, default *.ant */
		'extension' => 'mytmpl',
		/* ignore caching, if option equal true, default false */
		'debug' => true, 
		/* if equal true - ignore rendering and always 
		   try load from cache, use in production for better performance, 
		   default false */
		'freeze' => true
	]);

Basic

Simple usage example:

require 'vendor/autoload.php';

use Ant\Ant;

echo Ant::init()
  ->get('index')
  ->assign([
    'title' => "Hello, I'm ANT",
    'features' => [
    	'simple',
    	'flexible',
    	'awesome'
    ]
  ])
  ->draw();

Create template:

// index.ant
<html>
  <head>
    <title>{{ $title }}</title>
  </head>
  <body>
    List of features
    <ul>
    @foreach ($features as $item)
      <li>{{ $item }}</li>
    @endforeach
    </ul>
  </body>
</html>

Project Structure

We recommend use the next folders structure:

views/
├── header.ant
├── content/
│   ├── about.ant
│   ├── news.ant
│   ├── products/
│   │   ├── search.ant
│   │   └── list.ant
│   ├── contacts.ant
│   └── suport.ant
├── index.ant
├── menu.ant
└── footer.ant

Use nested folders for emulating namespaces, for folders and template name use lowercase symbols a...z and dash -. Don't use a dot . because it will be transformed into invalid path.

For resolve template path ANT use dot.notation.

// will be transformed into /content/products/list.ant
Ant::init()->get('content.products.list')

Events

Here next types of events can be triggered:

  • build - before template parse
  • prepare - after parse
  • exec - after rendering

For cancel event bubbling use preventParentEvent method.

//global events
$ant = Ant::init()->setup([/*...*/]);

$eid = $ant->bind('build', function ($s) { /*...*/ });
$eid = $ant->bind('prepare', function ($s) { /*...*/ });
$eid = $ant->bind('exec', function ($s) { /*...*/ });

//unbind event
$ant->unbind($eid);

//local events
$ant = Ant::init();

$ant->get('template');
$ant->assign($data);

$eid = $ant->on('build', function ($s) { /*...*/ });
$eid = $ant->on('prepare', function ($s) { /*...*/ });
$eid = $ant->on('exec', function ($s) { /*...*/ });

//unbind local event
$ant->off($eid);

//cancel global event
$ant->preventParentEvent($event);

$ant->draw();

Logic

Logic - special layer between model and view in classic MVC pattern.
Logic layer process variables and pass it to template. If logic path is defined, use folder structure same as view:

views/
│   ├──path/
│   │   ├──to/
│   │   │   ├──...
└── └── └── └──template.ant

logic/
│   ├──path/
│   │   ├──to/
│   │   │   ├──...
└── └── └── └──template.php

If logic file is exists, ANT include and process it.

Another way use logic - define logic path manually:

echo Ant::init()
	->get('template')
	->logic($path)
	->assign([
		'date' => '2002-05-04',
		'name' => 'john',
		'size' => 45654321
	])
	->draw();
// /logic/path/to/template.php
$date = $this->date($date, 'd/m/Y');
$name = $this->capitalize($name);
$size = $this->bytesHuman($size);

Extends

You can define your own template syntax:

Ant::init()
	...
	->rule($rx, $call)

For example we define comments syntax like {!-- ... --!} that will be transformed into <!-- ... -->.

Ant::init()
	...
	->rule('~{!--.+?--!}/ms~', function($e) {
		return '<!-- ' . $e[0] . '-->';
	})

API

Complete list of API:

class Ant
{
	/*
	 * Create new instance
	 */
	function init();
	
	/*
	 * Return settings params, if $name = false - return all
	 *
	 * @param string $name - settings name
	 */
	function settings($name = false);

	/*
	 * Check template exists
	 *
	 * @param string $name - template name
	 */
	function has($name);

	/*
	 * Select template
	 *
	 * @param string $name - template name
	 */
	function get($name);
	
	/*
	 * Load template from string
	 *
	 * @param string $s - template string
	 */
	function fromString($s);

	/*
	 * Load template from file
	 *
	 * @param string $path - path to template file
	 */
	function fromFile($path);

	/**
	 * Accept template variables
	 *
	 * @param array $data - variables
	 */
	function assign(array $data = array());

	/**
	 * Render template
	*/
	function draw();

	/*
	 * Helper wrapper for Ant::init()->get()->assign()->draw()
	 *
	 *	@param string $path - template name
	 */
	function view($name);

	/*
	 * @param string $path - path to template
	 * @param array $assign - variables
	 */
	function view($name, array $assign);

	/*
	 * @param string $path - path to template
	 * @param string $logic - path to logic file
	 */
	function view($name, $logic);

	/*
	 * @param string $path - path to template
	 * @param array $assign - variables
	 * @param string $logic - path to logic file
	 */
	function view($name, array $assign, $logic);
}

Variables

Define template variable by double curly brackets, by default ANT escape all variables:

{{ $name }}

If you don't wanna escape value, use 3 curly brackets syntax:

{{{ $name }}}

Handle empty values:

{{ $name or 'Default' }}

Array values can be accessed by dot notation syntax:

{{ $array.dot.notation }}

Object values can be accessed by arrows:

{{ $objects->arrow->notaion }}

Simple access to global variables:

// $_GET['name']
{{ $.get.name }}
// $_SERVER['DOCUMENT_ROOT']
{{ $.server.DOCUMENT_ROOT }}
// $GLOBALS['foo']
{{ $.globals.foo }}
// shortcut helper
{{ $.ant }}

$.scope - special variable that contains all defined variables in scope:

@each('view.path', $comments, 'com', $.scope)

@import('view.path', $.scope)

Easy plugin access:

$.plugin->youtube('6v2L2UGZJAM')

Comment syntax:

{{-- comments never output --}}

For skipping variable parsing use single backslash, now you can safely use Angular variables:

<div>
	<label>Name:</label>
	<input type="text" ng-model="yourName" placeholder="Enter a name here">
	<hr>
	<h1>Hello \{{yourName}}!</h1>
</div>

Control

ANT use alternative PHP syntax for control structures.

@if

@if ($condition)
	<div>Block One</div>
@elseif ($alter)
	<div>Block Two</div>
@else
	<div>Block Three</div>
@endif

@unless

@unless ($is_mobile)
	<div>You use desktop version</div>
@endunless

@switch

@switch ($fruit)
	@case ('apple')
		<img src="apple.png" />
	@break

	@case ('pear')
		<img src="pear.png" />
	@break

	@default
		<img src="no-image.png" />
	@break
@endswitch

@for

<ul>
@for ($i = 0; $i < 10; $i++)
	<li>{{ $i }}</li>
@endfor
</ul>

@while

@while ($condition)
	...
@endwhile

@foreach

@foreach ($comments as $com)
	<div class="comment-item">
		<div class="comment-date">{{ $com.date }}</div>
		<div class="comment-text">{{ $com.text }}</div>
	</div>
@endforeach

Inside @foreach and @forelse loops you can get iterator state, ANT wrap collection by Ant\StateIterator and restore value after loop is end.

@foreach ($collection as $item)
	// check first iteration
	@if ($collection->isFirst())
		...
	// check last iteration
	@if ($collection->isLast())
		...
	// is between first and last
	@if ($collection->isMiddle())
		...
	// is iteration number is odd
	@if ($collection->isOdd())
		...
	// is iteration number is even
	@if ($collection->isEven())
		...
	// is iteration number divisible by number
	@if ($collection->isDivisible($by))
		...
@endforeach

@forelse

@forelse ($comments as $com)
	...
@empty
	<div>No comments yet :(</div>
@endforelse

@each

@each ('view.path', $comments, 'com')
...
//view.path
<div class="comment-item">
	<div class="comment-date">{{ $com.date }}</div>
	<div class="comment-text">{{ $com.text }}</div>
</div>

@each($view, $collection[,$item[,$scope]])

  • $view - template name
  • $collection - data
  • $item - variable name, default item
  • $scope - additional data

@import

Shortcut to Ant::view.

<!DOCTYPE html>
<html>
<head>
	<title>Include Blocks</title>
</head>
<body>
	@import ('header')
	...
	@import ('content')
	...
	@import ('footer')
</body>
</html>

@widget

Equivalent to @import.

@skip

For ignore parsing use @skip tag.

@skip
  {{ $vaiable }}
@endskip

@php

@php
  // multiline php code
  ...
@endphp

Inheritance

Define base layout:

// layout.ant
<!DOCTYPE html>
<html>
<head>
	<title>Inheritance Example</title>
	@block('scripts')
		@js('/path/to/script.js')
	@endblock

	@block('styles')
		@css('/path/to/style.css')
	@endblock
</head>
<body>
	@block('contents')
		<main>Content will be replaced</main>
	@endblock
</body>
</html>

Extends:

// inject.ant
@extends('layout')

@inject('scripts')
	@js('/path/to/another.js')
@append

@inject('styles')
	@css('/path/to/another.css')
@prepend

@inject('contents')
	<main>Contents</main>
@rewrite

Final page:

<!DOCTYPE html>
<html>
<head>
	<title>Inheritance Example</title>
	<script type="text/javascript" src="/path/to/script.js"></script>
	<script type="text/javascript" src="/path/to/another.js"></script>
	<link type="text/css" rel="stylesheet" href="/path/to/another.css" />
	<link type="text/css" rel="stylesheet" href="/path/to/style.css" />
</head>
<body>
	<main>Contents</main>
</body>

Functions

For calling defined functions use next syntax:

//short syntax
{{ ::functionName($param) }}

//long syntax
{{ $this->ant->functionName($param) }}

For creating new function use Ant::share.

//define function
Ant::share('pow', function($n) {
	return $n * $n;
});

//check function exists
Ant::isShared('pow')

//call
{{ ::pow(5) }}

doctype

doctype($type = 'HTML5')

Description

Return DOCTYPE declaration

Parameters

$type
One of values
  • HTML5
  • XHTML11
  • XHTML1_STRICT
  • XHTML1_TRANSITIONAL
  • XHTML1_FRAMESET
  • XHTML_liASIC1
  • HTML4_STRICT
  • HTML4_LOOSE
  • HTML4_FRAMESET

js

js($src, $defer = "")

// or you can use shortcut
@js($src, $defer = "")

Description

Embed script

Parameters

$src
Path to script
$defer
Additional attributes: defer or async

css

css($href, $media = "")

//or you can use shortcut
@css($href, $media = "")

Description

Embed style

Parameters

$href
Path to stylesheet
$media
Media values

escape

escape($string, $double = false)

Description

Escape string

Parameters

$string
The input string
$double
Process escaped entity, default false

decode

decode($string)

Description

Unescape string

Parameters

$string
The input string

upper

//hello => HELLO
upper($string)

Description

Make a string uppercase

Parameters

$string
The input string

lower

// HELLO => hello
lower($string)

Description

Make a string lowercase

Parameters

$string
The input string

isBlank

isBlank($what)

Description

Return true if variable is null, false, empty string, string with whitespaces only, or empty array

Parameters

$what
Variable for check

isEmpty

isEmpty($what)

Description

Return true if variable is 0, null, false, empty string, string with whitespaces only, or empty array

Parameters

$what
Variable for check

date

date($date, $format = 'Y-m-d H:i:s', $tz = null)

Description

Print date in given format

Parameters

$date
Date value accepted by DateTime
$format
Output format
$tz
Timezone name

capitalize

// hello => Hello
capitalize($string)

Description

Capitalize string

Parameters

$string
The input string

capitalizeAll

// hello world => Hello World
capitalizeAll($string)

Description

Capitalize all words in string

Parameters

$string
The input string

whitespace

// H  el  lo => H el lo
whitespace($string)

Description

Replaces all white-space characters sequence, with single white-space

Parameters

$string
The input string

limit

// Lorem ipsum dolor sit amet, cons... 
limit($string, $limit = 250, $postfix = '...')

Description

Limit string length

Parameters

$string
The input string
$limit
Number of characters
$postfix
String decorator

limitWords

// Lorem ipsum dolor sit amet, consectetuer...
limitWords($string, $limit = 250, $postfix = '...')

Description

Limit string length, non word breaking

Parameters

$string
The input string
$limit
Number of characters
$postfix
String decorator

limitMiddle

// Lorem ipsum dolor...te feugait nulla facilisi.
limitMiddle($string, $limit = 250, $postfix = '...')

Description

Limit string length, by middle

Parameters

$string
The input string
$limit
Number of characters
$postfix
String decorator

lorem

// Lorem ipsum dolor sit amet, consectetuer
lorem($limit = 544)

Description

Fake text generator

Parameters

$limit
Fake text length

number

// 3548791 => 3 548 791
number($num, $precision = 0)

Description

Format number

Parameters

$num
Number
$precision
Precision

bytesHuman

// 4637467 => 4.42 MB
bytesHuman($size, $precision = 2)

Description

Human readable in bytes

Parameters

$size
Size in bytes
$precision
Precision

roundHuman

// 637467 => 637.47 K
roundHuman($size, $precision = 2)

Description

Format number

Parameters

$size
Number
$precision
Precision

ordinal

// 25 => 25th
ordinal($num)

Description

Create ordinal number

Parameters

$num
Number

unicode

// I \u2665 HTML => I ♥ HTML
unicode($string)

Description

Conver unicode sequence to html entity

Parameters

$string
Sequence

url

// ['foo' => 'bar', 'baz' => 'quux'] => foo=bar&baz=quux
url(array $params)

Description

Build url string

Parameters

$params
Params

iterable

iterable($instance)

Description

Check if variable can be used in loops

Parameters

$instance
Variable to check

count

count($instance)

Description

Count collection items

Parameters

$instance
Variable to check

template

template($tmpl, $params...)
//ANT is simple, flexible and awesome
template('ANT is {1}, {2} and {3}', 'simple', 'flexible', 'awesome')

Description

Build template with placeholders

Parameters

$tmpl
Template string
$params
Params list

Plugins

ANT provide access for dozen build-in plugins. For activate it use next example:

use Ant\Ant;

// activate plugin
$ant = Ant::init()
	->setup([
		...
	])
	->activate($pluginOne)
	->activate($pluginTwo)
	->activate($pluginThree);

// check is plugin activated
$ant->isActivated($plugin)

// deactivate plugin
$ant->deactivate($plugin)

You can simple define your own plugin like this:

// plugin definition
class MyPlugin
{
	public function __construct(array $options)
	{
		/*...*/
	}

	public function __invoke($param)
	{
		/*...*/
	}

	public function methodName($param)
	{
		/*...*/
	}
}

// global init
Ant::init()
	->setup([
		...
	])
	->register('myplugin', new MyPlugin($options));

// call __invoke
{{ $.plugin->myplugin($param) }}
// call methodName
{{ $.plugin->myplugin->methodName($param) }}

Asset

Append file modification time to given path, useful for cache manage. If plugin activated, automatically process path in ::js and ::css functions.

$ant->activate('Asset')
// /path/to/script.js?1463545199
{{ $.plugin->asset($path) }}
// <script src="/path/to/script.js?1463545199"></script>
@js($path)

Compressor

Compress HTML code.

$ant->activate('Compressor')

Faker

Wrapper for https://github.com/fzaninotto/Faker.
You need install it by composer require fzaninotto/faker.

$ant->activate('Faker', ['locale' => 'en_US'])
// 'Lucy Cechtelar'
{{ $.plugin->faker->name  }}

Google Analytics

Embed Google Analytics script https://www.google.com/analytics.

$ant->activate('GoogleAnalytics')

{{{ $.plugins->ga($code, $domain = '') }}}

Haml

Haml parser. You need install it by composer require hamlphp/hamlphp.

$ant->activate('Haml')

InlineCSS

Wrapper for InlineCss. You need install it by composer require undercloud/inlinecss.

$ant->activate('InlineCSS')

{{ $.plugin->css(['color' => 'red', 'font-weight' => 'bold']) }}

Jade

Jade parser. You need install it by composer require undercloud/picojade.

$ant->activate('Jade')

Lang

Wrapper for Lang. You need install it by composer require undercloud/lang.

$ant->activate('Lang'[,$options])
// you can use $.lang shortcut helper
{{ $.lang('message.name') }}

Leaf

Wrapper for Leaf. You need install it by composer require undercloud/leaf.

$ant->activate('Leaf')

Markdown

Markdown parser. Port for parsedown. You need install it by composer require erusev/parsedown.

$ant->activate('Markdown')

Validator

HTML validator and linter.

// basic validator, check DOM tree only
$ant->activate('Validator')
// strict, check deprecated tags and attrs, non standard tags, required attrs etc...
$ant->activate('Validator', ['strict' => true])

YouTube

Embed Youtube video.

$ant->activate('YouTube')
// extended setup
$ant->activate('YouTube', ['params' => [...], 'attrs' => [...]])
// embed video
{{{ $.plugin->youtube($video_id[,$options]) }}}
// get preview image url, $size - one of values: hq, mq, sd, maxres or empty for default
{{ $.plugin->youtube->preview($video_id[,$size]) }}