fe3dback/kx-draw

PHP/JS handlebars wrapper with reactive update

dev-master 2017-10-09 12:53 UTC

README

Build Status Coverage Status

Handlebars Render (PHP/JS)

This is reactive two side template library for handlebars. One template you can render on both sides:

  • backend [PHP]
  • frontend [JS] (optional)

Lib is wrapper of fastest handlebars implementation, based on: zordius/lightncandy

Unit testing Regression testing License Total Downloads

Install

$ composer require fe3dback/kx-draw
Requirements [PHP side]:

Use

Prepare directories

  • First of all you need to make tmp folder inside your project, kxdraw will be store all cache data to optimize render speed. Check RWO access to this directory.

  • Also you need some folder for templates.

Something like this:

- my_project_root
|- example.php              // some php script
|- tmp/draw                 // any cache will be here
|- public/templates/*.hbs   // templates folder

Require lib

code from example.php

use KX\Template\Builders\EngineFactory;
use KX\Template\Draw;

require_once 'vendor/autoload.php';

$draw = new Draw
(
    (new EngineFactory())
        ->setExt('hbs')                         // templates file extension (*.hbs)
        ->setCacheDirReal($cacheDir)            // cache directory (we can safely delete dir, and cache will be rebuild)
        ->setTemplatesDirReal($templatesDir)    // where our templates live
        ->setUseCache(true)                     // recommend to turn ON this feature (compile only first time)
        ->setUseMemCache(true)                  // recommend to turn ON this feature (helpful for loops)
        ->build()
);

Ok, we got $draw class, so we can render some template:

code from public/templates/hello.hbs

<b>Hello {{name}}!</b>

code from example.php

$html = $draw->render('hello', 1, [
    'name' => 'world'
]);

What we use:

  • 'hello' - this is template file name (without extension)
  • 1 - unique render id. Good idea to use EntityID (productId, userId, articleId, etc..) for that.
  • ['name'=>'world'] - data used in template

Result will be in $html:

<b>Hello world!</b>

Global scope use

In some case we want to use DrawLib from any application place:

Put this code in any shared file, executed from every other script (common.php, etc..)

/**
 * Get draw object
 * global scope wrapper
 *
 * @return Draw
 */
function KXDraw(): Draw
{
    global $__kxDrawEntity;

    if (is_null($__kxDrawEntity))
    {
        $cacheDir = '/'; // todo replace to your dir
        $templatesDir = '/'; // todo replace to your dir
        
        // make draw object, we can use only this class directly
        $__kxDrawEntity = new Draw
        (
            (new EngineFactory())
                ->setExt('hbs')                         // templates file extension (*.hbs)
                ->setCacheDirReal($cacheDir)            // cache directory (we can safely delete dir, and cache will be rebuild)
                ->setTemplatesDirReal($templatesDir)    // where our templates stored
                ->setUseCache(true)                     // recommend to turn ON this feature (compile only first time)
                ->setUseMemCache(true)                  // recommend to turn ON this feature (helpful for loops)
                ->build()
        );
    }

    return $__kxDrawEntity;
}

Use:

$html = KXDraw()->render('hello', 1, [
    'name' => 'world'
]);

Partials

Before use partials in our templates, we need to mark some templates (or entire folders as partials).

// mark /templates/common/header.hbs
KXDraw()->addPartial('/common/header');

// mark /templates/shared/*/*
KXDraw()->addPartialsDirectory('shared');

Now any marked templates can be used as partials:

code from public/templates/hello.hbs

<b>Hello {{> shared/name}}!</b>

code from public/templates/shared/name.hbs

<i>{{name}}</i>

code from example.php

$html = KXDraw()->render('hello', 1, [
    'name' => 'world'
]);

Result will be in $html:

<b>Hello <i>world</i>!</b>

Templates and Reactivity

  • All templates should have only one parent. (like in react). For example:

This is OK:

<div>..some_content..</div>

This will be broken:

<div>..some_content1..</div>
<div>..some_content2..</div>

In case when template have many nodes, we can wrap with some another div/span/etc..

This is OK:

<div>
    <div>..some_content1..</div>
    <div>..some_content2..</div>
</div>

Export to JS

Requirements [JS side]:

Handlebars can be installed with many variants:

Include
  • place JQ and handlebars.js anywhere in markup (for example before < / body> tag closing)
  • AFTER place js draw implementation and exported data:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.7/handlebars.min.js"></script>
<script type="text/javascript" src="/vendor/fe3dback/kx-draw/draw.js"></script>

<!-- after export no more rendering allowed, this should be last call to KXDraw -->
<?=KXDraw()->exportToJS()?>

JS Usage

Go to page with templates and lib, and try in console:

KXDraw
// KXDrawRender {templates: Object, data: Object, partials: Object}

If lib included correctly, this object should contain all data, templates and partials from backend

Methods:

KXDraw.getRawData()

Return all data used in backend

KXDraw.getRawData()
// Object {hello: Object}

KXDraw.getRawPartials()

Return all partials

KXDraw.getRawPartials()
// Object {shared/name: "<i>{{name}}</i>"}

KXDraw.getRawTemplates()

Return all raw templates from backend files

KXDraw.getRawTemplates()
// Object {hello: "<b>Hello {{> shared/name}}!</b>"}

KXDraw.update(templateName, uniqueId, data = {}, assign = true)

Update html template on page, and template data.

  • string templateName - path to templateFile (relative without extension)
  • string uniqueId - id from backend
  • object data - object with fields
  • bool assign DEF: TRUE - if true, update will combine old data with new data
KXDraw.update('hello', 1, {name:"KXRender"});
// true

Assign example

// old data:
{
    a: 1, 
    b: 2
}

// new data:
{
    b: 4
}

// RESULT WITH ASSIGN:
{
    a: 1, 
    b: 4
}

// RESULT WITHOUT ASSIGN:
{
    b: 4
}

KXDraw.getDataByUniqId(templateName, uniqueId)

Get stored data from used template

  • string templateName - path to templateFile (relative without extension)
  • string uniqueId - id from backend
KXDraw.getDataByUniqId('hello', 1);
// Object {
// name: "world", 
// _kx_draw_template_name: "hello", 
// _kx_draw_unique_id: "1"
// }

KXDraw.getNodeByUniqId(templateName, uniqueId)

Get Jquery node object

  • string templateName - path to templateFile (relative without extension)
  • string uniqueId - id from backend
KXDraw.getNodeByUniqId('hello', 1);
// [b, prevObject: r.fn.init(1)]
// > 0: b
// > length: 1

Examples

see examples folder.