{"id":36388067,"url":"https://github.com/affinity4/template","last_synced_at":"2026-01-11T15:05:02.851Z","repository":{"id":56941674,"uuid":"91277658","full_name":"affinity4/template","owner":"affinity4","description":"Simple extendable template engine with optional syntax which is easy to learn. Allows you to use plain PHP also.","archived":false,"fork":false,"pushed_at":"2024-02-18T14:26:43.000Z","size":40,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-22T11:39:35.007Z","etag":null,"topics":["affinity4","php","template-engine","template-language"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/affinity4.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-14T23:29:24.000Z","updated_at":"2022-05-25T17:15:15.000Z","dependencies_parsed_at":"2022-08-21T07:50:22.771Z","dependency_job_id":null,"html_url":"https://github.com/affinity4/template","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/affinity4/template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/affinity4%2Ftemplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/affinity4%2Ftemplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/affinity4%2Ftemplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/affinity4%2Ftemplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/affinity4","download_url":"https://codeload.github.com/affinity4/template/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/affinity4%2Ftemplate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28309752,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-11T14:58:17.114Z","status":"ssl_error","status_checked_at":"2026-01-11T14:55:53.580Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["affinity4","php","template-engine","template-language"],"created_at":"2026-01-11T15:05:02.206Z","updated_at":"2026-01-11T15:05:02.846Z","avatar_url":"https://github.com/affinity4.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Template\n\nFull-featured template engine with optional syntax which is easy to learn. Can use plain PHP also.\n\n## Features\n - HTML Comment syntax\n - Can use plain PHP in templates if needed\n - Add new syntax if needed.\n\n## Installation\n\nAffinity4/Template is available via composer:\n\n```bash\ncomposer require affinity4/template\n```\n\nor\n\n```json\n{\n    \"require\": {\n        \"affinity4/template\": \"^1.1\"\n    }\n}\n```\n\n## Syntax\nOutput a variables:\n\n```html\n\u003ch1\u003e\u003c!-- :title --\u003e\u003c/h1\u003e\n```\n\nSet a variable:\n\n```html\n\u003c!-- :showTitle = true --\u003e\n```\n\nTo get an array item by key, such as `$post['title']`:\n\n```html\n\u003c!-- :post.title --\u003e\n```\n\nIf statement:\n\n```html\n\u003c!-- @if :showTitle is true and :something is false or :somethingElse --\u003e\n    \u003ch1\u003e\u003c!-- :title --\u003e\u003c/h1\u003e\n\u003c!-- @/if --\u003e\n\n\u003c!-- @if :showTitle --\u003e\n    \u003ch1\u003e\u003c!-- :title --\u003e\u003c/h1\u003e\n\u003c!-- @elseif :something and :showTitle --\u003e\n    \u003ch1\u003e\u003c!-- :title --\u003e\u003c/h1\u003e\n    \u003ch2\u003eSomething\u003c/h1\u003e\n\u003c!-- @else --\u003e\n    \u003ch1\u003eDefault Title\u003c/h1\u003e\n\u003c!-- @/if --\u003e\n```\n\nForeach loop:\n\n```html\n\u003cul\u003e\n\u003c!-- @each :item in :items --\u003e\n    \u003cli\u003e\u003c!-- :item --\u003e\u003c/li\u003e\n\u003c!-- @/each --\u003e\n\u003c/ul\u003e\n\n\u003c!-- @each :id, :post in :posts --\u003e\n\u003carticle\u003e\n\u003ch1\u003e\u003c!-- :post.title --\u003e\u003c/h1\u003e\n\u003cdiv\u003e\u003c!-- :post.content --\u003e\u003c/div\u003e\n\u003c/article\u003e\n\u003c!-- @/each --\u003e\n\n```\n__NOTE:__ Can be `@foreach` also.\n\nWhile loop:\n\n```html\n\u003c!-- :i = 1 --\u003e\n\u003c!-- @while :i \u003c= count(:items) --\u003e\n    Number: \u003c!-- :i --\u003e\u003cbr /\u003e\n\u003c!-- :i++ --\u003e\n\u003c!-- @/while --\u003e\n\n```\n\nFor loop:\n\n```html\n\u003c!-- @for :i = 1; :i \u003c= 3; :i++ --\u003e\n    Number: \u003c!-- :i --\u003e\u003cbr /\u003e\n\u003c!-- @/for --\u003e\n```\n\n## Layouts and Blocks\n\nYou can extend master layouts the same way as you would in any other template engine such as Twig or Blade.\n\nCreate a master layout with sections to be overridden in each view file:\n\nFile: `views/layout/master.php`\n\n```html\n\u003c!DOCKTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003e\u003c!-- @block title --\u003eThis can be overridden\u003c!-- @/block --\u003e: Site description\u003c/title\u003e\n    \n    \u003clink href=\"/assets/css/main.css\" rel=\"stylesheet\"\u003e\n    \u003c!-- @block css --\u003e\n    \u003c!-- Each view can add custom CSS here --\u003e\n    \u003c!-- @/block --\u003e\n    \n    \u003cscript src=\"/assets/js/jquery.js\"\u003e\u003c/script\u003e\n    \u003c!-- @block js-head --\u003e\n    \u003c!-- Each view can add custom JS here --\u003e\n    \u003c!-- @/block --\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cmain\u003e    \n        \u003ch1\u003e\u003c!-- @block page-title --\u003eDefault Page\u003c!-- @/block --\u003e\u003c/h1\u003e\n        \n        \u003c!-- @block content --\u003e\n        \u003cp\u003ePage content goes here...\u003c/p\u003e\n        \u003c!-- @/block --\u003e\n    \u003c/main\u003e\n\n    \u003c!-- @block js-footer --\u003e\n    \u003c!-- Each view can add custom JS here --\u003e\n    \u003c!-- @/block --\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nThen in you view:\n\nFile: `views/home.php`\n\n```html\n\u003c!-- @extends layout/master.php --\u003e\n\n\u003c!-- @block title --\u003e\u003c!-- :page_title --\u003e\u003c!-- @/block --\u003e\n\n\u003c!-- @block css --\u003e\n\u003clink href=\"/assets/css/home.css\" rel=\"stylesheet\"\u003e\n\u003c!-- @/block --\u003e\n\n\u003c!-- @block page-title --\u003e\u003c!-- :page_title --\u003e\u003c!-- @/block --\u003e\n\n\u003c!-- @block content --\u003e\n\u003cp\u003eThis is the homepage\u003c/p\u003e\n\u003c!-- @/block --\u003e\n```\n\nThen simply render the view:\n\nFile: `index.php`\n\n```php\nuse Affinity4\\Template;\n\n$template = new Template\\Engine(new Template\\Syntax);\n\n$tempalte-\u003erender('views/home.php', ['page_title' =\u003e 'Home']);\n```\n\n## Usage\nTo render a template:\n\n```php\nuse Affinity4\\Template;\n\n$template = new Template\\Engine(new Template\\Syntax);\n\n$template-\u003erender('views/home.php', ['title' =\u003e 'Home Page']);\n```\n\nIf you want to add new syntax you can use the `addToken` method after initializing the template engine.\n\n```php\nuse Affinity4\\Template;\n\n$template = new Template\\Engine(new Template\\Syntax);\n\n$template-\u003eaddRule('/\\{\\{ ([\\w\\d+]) \\}\\}/', '\u003c?= $$1 ?\u003e');\n\n$template-\u003erender('views/home.php', ['title' =\u003e 'Home Page']);\n```\n\nYou can also pass a callable as the second argument to the `addToken` method to use `preg_replace_callback` instead for the replacement.\n\n```php\nuse Affinity4\\Template;\n\n$template = new Template\\Engine(new Template\\Syntax);\n\n$template-\u003eaddRule('/\\{\\{ ([\\w\\d]+) \\}\\}/', function ($statement) {\n    return '\u003c?php echo $' . $statement[1] . ' ?\u003e'; \n});\n\n$template-\u003erender('views/home.php', ['title' =\u003e 'Home Page']);\n``` \n\n## Overriding Syntax\n\nOne thing which is quite original about Affinity4 Template is that it allows you to replace the Syntax class with your won simple class to create a template language of your own. \n\nIt easy to add all the features currently in Affinity4 Template by simply extending the Affinity4\\Template\\Tokenizer class and implementing the Affinity4\\Template\\SyntaxInterface. From there you need only add rules for variables, loops etc. and extend and block syntax. If you do not add extend or block rules that functionality will simply not be available.\n \nHere is an example of creating a Blade style syntax of your own\n\n```php\n\u003c?php\nnamespace Your\\Template\\Syntax\\Blade2;\n\nuse Affinity4\\Template;\n\nclass Blade2 extends Affinity4\\Template\\Tokenizer implements Affinity4\\Template\\SyntaxInterface\n{\n    public function __construct()\n    {\n        $this-\u003eaddRule('/\\{\\{ ?(\\$.*) ?\\}\\}/', '\u003c?php echo htmlspecialchars($1, ENT_QUOTES, 'UTF-8'); ?\u003e');\n        \n        $this-\u003eaddRule('/@if ?\\(\\(.*))/', '\u003c?php if ($1) : ?\u003e');\n        $this-\u003eaddRule('/@elseif ?\\(\\(.*))/', '\u003c?php elseif ($1) : ?\u003e');\n        $this-\u003eaddRule('/@else/', '\u003c?php else : ?\u003e');\n        $this-\u003eaddRule('/@endif/', '\u003c?php endif; ?\u003e');\n        \n        $this-\u003eaddRule('/@foreach ?\\(\\(.*))/', '\u003c?php foreach ($1) : ?\u003e');\n        $this-\u003eaddRule('/@endforeach/', '\u003c?php foreach ($1) : ?\u003e');\n        \n        // For, while etc...\n        \n        $this-\u003eaddExtendsRule('/@extends\\((.*)\\)/');\n        $this-\u003eaddSectionRule('/@section\\('(.*)'\\)/', '/@endsection/');\n    }\n}\n\n```\n\nYou then simply use dependency injection when calling the Template Engine class\n\n```php\nrequire_once __DIR__ . '/vendor/autoload.php';\n \nuse Affinity4\\Template\\Engine;\nuse Your\\Template\\Syntax\\Blade2;\n\n$blade2 = new Engine(new Blade2);\n$blade2-\u003erender('views/home.blade', ['title' =\u003e 'Blade 2']);\n```\n\nThe your layout template (views/layout/master.blade) can be:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003e@section('title') Default to be overriden @endsection\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003ch1\u003e\n    @section('title')\n        Title here...\n    @endsection\n    \u003c/h1\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nIn views/home.blade...\n\n```html\n@extends('layouts/master.blade')\n\n@section('title')\n  {{ $title }}\n@endsection\n```\n\n## Tests\n\nRun tests:\n\n```bash\nvendor/bin/phpunit\n```\n\n## Licence\n(c) 2017 Luke Watts (Affinity4.ie)\n\nThis software is licensed under the MIT license. For the\nfull copyright and license information, please view the\nLICENSE file that was distributed with this source code.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faffinity4%2Ftemplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faffinity4%2Ftemplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faffinity4%2Ftemplate/lists"}