{"id":20741149,"url":"https://github.com/micky-n/mkyengine","last_synced_at":"2025-10-17T05:27:52.371Z","repository":{"id":44547740,"uuid":"455064623","full_name":"Micky-N/mkyengine","owner":"Micky-N","description":"Mky Template Engine","archived":false,"fork":false,"pushed_at":"2023-08-07T19:21:37.000Z","size":118,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"1.x","last_synced_at":"2025-09-29T20:59:16.324Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/Micky-N.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-03T07:11:05.000Z","updated_at":"2022-11-07T19:18:10.000Z","dependencies_parsed_at":"2024-11-17T06:36:13.498Z","dependency_job_id":"ef86e876-f183-4c62-9197-2e45fa5e2da0","html_url":"https://github.com/Micky-N/mkyengine","commit_stats":{"total_commits":61,"total_committers":3,"mean_commits":"20.333333333333332","dds":0.3278688524590164,"last_synced_commit":"117cad44b3ba6e4ca26be70c39af1671fda8abc7"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Micky-N/mkyengine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Micky-N%2Fmkyengine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Micky-N%2Fmkyengine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Micky-N%2Fmkyengine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Micky-N%2Fmkyengine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Micky-N","download_url":"https://codeload.github.com/Micky-N/mkyengine/tar.gz/refs/heads/1.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Micky-N%2Fmkyengine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279289881,"owners_count":26141131,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-17T02:00:07.504Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-11-17T06:34:14.554Z","updated_at":"2025-10-17T05:27:52.356Z","avatar_url":"https://github.com/Micky-N.png","language":"PHP","readme":"# MkyEngine\n\n\u003e *PHP template engine by Micky-N*   \n\u003ca href=\"https://packagist.org/packages/micky/mkyengine\"\u003e\u003cimg src=\"https://img.shields.io/packagist/v/micky/mkyengine\" alt=\"Latest Stable Version\"\u003e\u003c/a\u003e [![Generic badge](https://img.shields.io/badge/licence-MIT-1abc9c.svg)](https://shields.io/)\n\nThe template engine uses the block and extension system to define the different parts of the view.\n```php\n// index.php\n\u003c?php $this-\u003eextends('layout') ?\u003e\n\n\u003c?php $this-\u003eblock('content') ?\u003e\n  \u003cp\u003econtent\u003c/p\u003e\n\u003c?php $this-\u003eendblock() ?\u003e\n```\n```php\n// layout.php\n\u003ch4\u003eLayout\u003c/h4\u003e\n\n\u003c?= $this-\u003esection('content') ?\u003e\n  \n\u003cp\u003eFooter\u003c/p\u003e\n```\n```html\n// render\n\u003ch4\u003eLayout\u003c/h4\u003e\n\n\u003cp\u003econtent\u003c/p\u003e\n\n\u003cp\u003eFooter\u003c/p\u003e\n```\n\n## Installation\n\n`composer require micky/mkyengine`\n\n## Usage\n\n### Directory Loader\n\nThe directory loader register view directory for template engine\n```php\n$loader = new \\MkyEngine\\DirectoryLoader('views_dir');\n```\nIf you want to define component or layout subdirectory use setComponentDir or setLayoutDir\n```php\n$loader-\u003esetComponentDir('components_dir')-\u003esetLayoutDir('layouts_dir');\n```\ncomponent directory will be `views_dir/components_dir` and layout directory will be `views_dir/layouts_dir`\n\n### Environment\n\nThe environment stores all directories with the namespace and file extension of the view, you can optionally define shared variables\n```php\n$context = [] // Shared environment variables, optional\n\n$environment = new \\MkyEngine\\Environment($loader, $context); \n```  \nBy default, the first namespace is root, you can add another directory loader and its namespace with the method `addLoader()`\n```php\n$environment-\u003eaddLoader('ns2', $loader2);\n\n// Check if loader exists\n$environment-\u003ehasLoader('ns2'); // true\n```\nTo use view, component or layout from another namespace use `@namespace:view`\n```php\n\u003c?= $this-\u003ecomponent('form') ?\u003e // From root namepsace\n\u003c?= $this-\u003ecomponent('@ns2:form') ?\u003e // From ns2 namespace\n```\n### View Compiler\n\nThe view compiler compiles the view by retrieving the blocks and displaying them in the layout sections. The first parameter is the environment, the second is the view to be displayed and the third is the view variables.\n```php\n$view = new \\MkyEngine\\ViewCompile($environment, 'index', [\n   'name' =\u003e 'Micky'\n]);\n```\nTo render the view use `render()` method\n```php\necho $view-\u003erender();\n```\n\n## Templating\n\n### Layout\n\nThe layout is a background for the views, you can define which parts of the layout will be filled by the view.\n```php\n// layout.php\n\u003ch4\u003eLayout\u003c/h4\u003e\n\u003c?= $this-\u003esection('content') ?\u003e\n\u003cp\u003eFooter\u003c/p\u003e\n```\nYou can define a default value in the section that will be used if no 'title' block is defined.\n```php\n// layout.php\n\u003c?= $this-\u003esection('title', 'default') ?\u003e\n```\nLayout view can extend another layout.\n```php\n// layout.php\n\u003c?php $this-\u003eextends('great-layout') ?\u003e\n\n\u003c?php $this-\u003eblock('title', 'new Title') ?\u003e\n\n\u003c?php $this-\u003eblock('content2') ?\u003e\n\n   \u003ch4\u003eLayout\u003c/h4\u003e\n   \u003c?= $this-\u003esection('content') ?\u003e\n\n\u003c?php $this-\u003eendblock() ?\u003e\n```\n```php\n// layout.php\n\u003c?= $this-\u003esection('title', 'title') ?\u003e  \n  \n\u003ch1\u003eLayout2\u003c/h1\u003e  \n  \n\u003c?= $this-\u003esection('content2') ?\u003e\n```\n\n### Block\n\n#### Extends\n\nExtends method is used to define the layout file.\n```php\n\u003c?php $this-\u003eextends('layout') ?\u003e\n```\n\nBlocks are a part of view use for layout. The param is the block name\n```php\n\u003c?php $this-\u003eextends('layout') ?\u003e\n\n\u003c?php $this-\u003eblock('content') ?\u003e\n  \u003cp\u003econtent\u003c/p\u003e\n\u003c?php $this-\u003eendblock() ?\u003e\n```\n\nYou can set a simple block with a second parameter\n```php\n\u003c?php $this-\u003eextends('layout') ?\u003e\n\n\u003c?php $this-\u003eblock('title', 'MkyFramework') ?\u003e\n```\n\nTo display this block use section() method in the layout with the block name to display\n```php\n// layout.php\n\u003ch4\u003eLayout\u003c/h4\u003e\n\u003c?= $this-\u003esection('content') ?\u003e\n\u003cp\u003eFooter\u003c/p\u003e\n```\nYou can define several blocks with the same name\n```php\n\u003c?php $this-\u003eblock('content') ?\u003e\n  \u003cp\u003econtent\u003c/p\u003e\n\u003c?php $this-\u003eendblock() ?\u003e\n\u003c?php $this-\u003eblock('content') ?\u003e\n  \u003cp\u003esecond part\u003c/p\u003e\n\u003c?php $this-\u003eendblock() ?\u003e\n```\nIt will show\n```html\n\u003cp\u003econtent\u003c/p\u003e\n\u003cp\u003esecond part\u003c/p\u003e\n```\nThanks to that, blocks can be conditioned by the method `if()`\n```php\n\u003c?php $this-\u003eblock('content')-\u003eif($condition) ?\u003e\n...\n\u003c?php $this-\u003eendblock() ?\u003e\n```\n\n### Injection\n\nThanks to injection method `$this-\u003einject` you can set object used for HTML template like number formatter or form builder as View property\n\nExample FormBuilder:\n```php\nclass FormBuilder\n{\n    public function open(array $attr): string\n    {\n        return \"\u003cform method='{$attr['method']}' action='{$attr['action']}'\u003e\";\n    }\n\n    public function input(string $type, string $name, string $value = ''): string\n    {\n        return \"\u003cinput type='$type' name='$name' value='$value'\u003e\";\n    }\n\n    public function submit(string $message, string $name = ''): string\n    {\n        return \"\u003cbutton type='submit'\" . ($name ? \" name='$name'\" : '') . \"\u003e$message\u003c/button\u003e\";\n    }\n\n    public function close(): string\n    {\n        return \"\u003c/form\u003e\";\n    }\n}\n```\nIn the view:\n\n```php\n// view.php\n\u003c?php $this-\u003einject('form', FormBuilder::class) ?\u003e\n```\nThe first parameter is the name of property you want to register in the view instance and the second is the class to instantiate, you can pass a class instance or a class name.\nYou will be able to use class via `$this-\u003enameOfProperty`\n\n```php\n\u003c?php $this-\u003einject('form', FormBuilder::class) ?\u003e\n\u003c?= $this-\u003eform-\u003eopen(['method' =\u003e 'POST', 'action' =\u003e '/create']) ?\u003e\n    \u003c?= $this-\u003eform-\u003einput('text', 'firstname', 'Micky') ?\u003e\n    \u003c?= $this-\u003eform-\u003einput('text', 'lastname', 'Ndinga') ?\u003e\n    \u003c?= $this-\u003eform-\u003esubmit('Save') ?\u003e\n\u003c?= $this-\u003eform-\u003eclose() ?\u003e\n```\nThe HTML rendering will be:\n```html\n\u003c!--Rendering--\u003e\n\u003cform method=\"POST\" action=\"/create\"\u003e\n    \u003cinput type=\"text\" name=\"firstname\" value=\"Micky\"\u003e\n    \u003cinput type=\"text\" name=\"lastname\" value=\"Ndinga\"\u003e\n    \u003cbutton type=\"submit\"\u003eSave\u003c/button\u003e\n\u003c/form\u003e\n```\n\n### Component\n\nThe component is a view piece, useful if you want to use it in several views.\n```php\n\u003c?= $this-\u003ecomponent('form') ?\u003e\n```\nYou can pass a variable to the component with the method `bind()`, the first parameter is the component variable and the second is the value.\n```php\n\u003c?= $this-\u003ecomponent('form')-\u003ebind('name', 'Micky') ?\u003e\n```\nYou can pass multiple variables to the component with the method `binds()`.\n```php\n\u003c?= $this-\u003ecomponent('form')-\u003emultipleBind(['name' =\u003e 'Micky', 'lastname' =\u003e 'Ndinga']) ?\u003e\n```\n\nSame as block class, components can be conditioned by the method `if()`\n```php\n\u003c?= $this-\u003ecomponent('form')-\u003eif($condition) ?\u003e\n```\nYou can repeat a component in loop with 2 methods:\n\n- for\n- each\n\n#### For loop\n\nThe first parameter is the number of iterations, the second is a callback that will be called at each iteration. In callback the first parameter is the view params, the second is the current loop index.\n\n*Example: in name-input.php component there a variable called 'name' for an input, with the callback each iterated component will have the name of the current user*\n```php\n// components/name-input.php\n\u003cinput value=\"\u003c?= $name ?\u003e\"/\u003e\n```\n```php\n\u003c?= $this-\u003ecomponent('name-input')-\u003efor(3, function(array $params, int $index) use ($users){  \n     $params['name'] = $users[$index]-\u003ename;  \n     return $params;  \n}) ?\u003e\n```\n#### Each\n\nWith the method `each()` , the component will iterate for each array value. The first parameter is the array and the second can be a callback, an array or a string.\n\n##### Callback\nThe `each()` callback is the same as the `for()` callback but with a third parameter that it's the array.\n```php\n\u003c?= $this-\u003ecomponent('name-input')-\u003eeach($users, function(array $params, int $index, array $users){\n    $params['name'] = $users[$index]-\u003ename;  \n    return $params;  \n}) ?\u003e\n```\n##### Array\nYou can bind variable with an array that index is the component variable and the value is the object property or array key of data `$users`\n```php\n\u003c?= $this-\u003ecomponent('name-input')-\u003eeach($users, ['name']) ?\u003e // 'name' =\u003e user-\u003ename\n\u003c?= $this-\u003ecomponent('name-input')-\u003eeach($users, ['name' =\u003e 'firstname']) ?\u003e // 'name' =\u003e user-\u003efirstname\n```\nIf you need to pass a nested value, you can do so by concatenating `address.postcode` it's equal to:\n\n- `$user-\u003e{address | getAddress() | magic getter for \"address\"}-\u003e{postcode | getPostcode() | magic getter for \"postcode\"}`  \n\nExample:  \n- `$user-\u003eaddress-\u003epostcode`\n- `$user-\u003egetAddress()-\u003epostcode`\n- `$user-\u003eaddress['postcode']`\n- `$user-\u003egetAddress()['postcode']`\n- `$user['address']-\u003epostcode`\n- `$user['address']['postcode']`\n\nAll properties and nested properties are accessible if the property exists or a getter, like for `postcode`, `getPostcode()` exists or a magic method exists \n\n##### String\nThe component may need the object or array as parameter (like one user of users), for that you can set in the parameter the name of current iterated data\n```php\n// components/user-input.php\n\u003cinput value=\"\u003c?= $user-\u003ename ?\u003e\"/\u003e\n\n// view\n\u003c?= $this-\u003ecomponent('user-input2')-\u003eeach($users, 'user') ?\u003e\n```\n\n##### Else component\nIf the data `$users` is empty you can set a third parameter as string to define the else component\n\n```php\n\u003c?= $this-\u003ecomponent('user-input')-\u003eeach($users, 'user', 'empty-user') ?\u003e\n```\n\n##### Component slot\nIn the case you have a component which you want to make the body dynamic like:\n\n```php\n// components/alert.php\n\u003cdiv class=\"alert alert-\u003c?= $type ?\u003e\"\u003e\n    \u003cdiv\u003e\n        \u003cp\u003e\u003c?= ucfirst($type) ?\u003e:\u003c/p\u003e\n        \u003c?= $this-\u003eslot('default') ?\u003e\n    \u003c/div\u003e\n    \u003c?php if ($this-\u003ehasSlot('confirm')): ?\u003e\n        \u003cbutton id=\"confirm\"\u003e\u003c?= $this-\u003eslot('confirm') ?\u003e\u003c/button\u003e\n    \u003c?php endif ?\u003e\n    \u003c?php if ($this-\u003ehasSlot('close')): ?\u003e\n        \u003cbutton id=\"close\"\u003e\u003c?= $this-\u003eslot('close') ?\u003e\u003c/button\u003e\n    \u003c?php endif ?\u003e\n\u003c/div\u003e\n```\nA simple alert component with a conditional button, to use this in your view, you have to set three slots: the `default`, `confirm` and `close` slot\n\n```php\n// view\n\u003c?php $this-\u003ecomponent('alert')-\u003ebind('type', 'danger') ?\u003e\n    this is an alert\n    \u003c?php $this-\u003eaddslot('confirm', 'confirm the alert') ?\u003e\n    // Or\n    \u003c?php $this-\u003eaddslot('confirm') ?\u003e\n        \u003cspan\u003econfirm\u003c/span\u003e the alert\n    \u003c?php $this-\u003eendslot() ?\u003e\n    \n    \u003c?php $this-\u003eaddslot('close', 'Close info') ?\u003e\n\n\u003c?php $this-\u003ecomponent('alert')-\u003eend() ?\u003e\n```\n\nThe HTML rendering will be:\n```html\n\u003cdiv class=\"alert alert-danger\"\u003e\n    \u003cdiv\u003e\n        \u003cp\u003eDanger:\u003c/p\u003e\n        this is an alert\n    \u003c/div\u003e\n    \u003cbutton id=\"confirm\"\u003e\u003cspan\u003econfirm\u003c/span\u003e the alert\u003c/button\u003e\n    \u003cbutton id=\"close\"\u003eClose info\u003c/button\u003e\n\u003c/div\u003e\n```\n\nAll texts not in a slot will be placed in the default slot. Slots can be conditional:\n\n```php\n\u003c?php $this-\u003eaddslot('close', 'Close info')-\u003eif($type == 'info') ?\u003e\n```\n\nYou can also make a default value for empty slot to avoid error message\n```php\n\u003c?= $this-\u003eslot('default', 'default text') ?\u003e\n```\n\n## Licence\n\nMIT","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicky-n%2Fmkyengine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicky-n%2Fmkyengine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicky-n%2Fmkyengine/lists"}