phpmustachemustache.php

PHP Mustache - multiple partials


I found this fiddle that shows how to include multiple partials in a Mustache template: http://jsfiddle.net/YW5zF/3/

I'm trying to convert this to PHP Mustache and having some difficulty. Can anyone help out here?

Essentially, I'm trying to understand how to reuse the input template several times in one template.

Here's my main template (contact.mustache):

<form id="contact-form" method="post" action="contact.php" role="form">
    <div class="messages"></div>
    <div class="controls">
        <div class="row">
            <div class="col-md-6">
                {{>input}}
            </div>
            <div class="col-md-6">
                {{>input}}
            </div>
        </div>
        <div class="row">
            <div class="col-md-6">
                {{>input}}
            </div>
            <div class="col-md-6">
                {{>input}}
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                {{>textarea}}
            </div>
            <div class="col-md-12">
                <input type="submit" class="btn btn-success btn-send" value="Send message">
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <p class="text-muted"><strong>*</strong> These fields are required.</p>
            </div>
        </div>
    </div>
</form>

Here's my input partial (input.mustache):

{{#input}}
    <div class="{{div_class}}">
        <label class="{{label_class}}" for="{{id}}">{{text}}</label>
        <input type="{{type}}" id="{{id}}" name="{{name}}" class="{{input_class}}" placeholder="{{placeholder}}" {{required}} data-error="{{data-error}}">
        <div class="{{line_class}}"></div>
    </div>
{{/input}}

Here's my textarea template (textarea.mustache)

{{#textarea}}
    <div class="{{div_class}}">
        <label class="{{label_class}}" for="{{id}}">{{text}}</label>
        <textarea id="{{id}}" name="{{name}}" class="{{input_class}}" placeholder="{{placeholder}}" rows="{{rows}}" {{required}} data-error="{{data-error}}"></textarea>
        <div class="{{line_class}}"></div>
    </div>
{{/textarea}}

Here's my PHP code to try to render it:

<?php

require_once __DIR__ . '/vendor/autoload.php';

$m = new Mustache_Engine;
    $data = array(
                    0 =>array(
                        "div_class"=>"form-group", 
                        "id"=>"form_name",
                        "type"=>"text",
                        "name"=>"name",
                        "placeholder"=> "Please enter your firstname *",
                        "required"=>"required='required'"
                        "data-error"=>"Firstname is required.",
                        "input_class"=>"form-control", 
                        "label_class"=>"floating-label",
                        "text"=>"Firstname *",
                        "line_class"=>"line-ripple",
                    ),
                    1=> array(
                        "div_class"=>"form-group", 
                        "id"=>"form_lastname",
                        "type"=>"text",
                        "name"=>"surname",
                        "placeholder"=> "Please enter your lastname *",
                        "required"=>"required='required'"
                        "data-error"=>"Lastname is required.",
                        "input_class"=>"form-control", 
                        "label_class"=>"floating-label",
                        "text"=>"Lastname *",
                        "line_class"=>"line-ripple",
                    ),
                    2 =>array(
                        "div_class"=>"form-group", 
                        "id"=>"form_email",
                        "type"=>"email",
                        "name"=>"email",
                        "placeholder"=> "Please enter your email *",
                        "required"=>"required='required'"
                        "data-error"=>"Valid email is required.",
                        "input_class"=>"form-control", 
                        "label_class"=>"floating-label",
                        "text"=>"Email *",
                        "line_class"=>"line-ripple",
                    ),
                    3 =>array(
                        "div_class"=>"form-group", 
                        "id"=>"form_phone",
                        "type"=>"tel",
                        "name"=>"phone",
                        "placeholder"=> "Please enter your phone",
                        "input_class"=>"form-control", 
                        "label_class"=>"floating-label",
                        "text"=>"Phone",
                        "line_class"=>"line-ripple",
                    ),
                    4 =>array(
                        "div_class"=>"form-group", 
                        "id"=>"form_message",
                        "name"=>"message",
                        "placeholder"=> "Message for me *",
                        "required"=>"required='required'"
                        "data-error"=>"Please,leave us a message.",
                        "input_class"=>"form-control", 
                        "label_class"=>"floating-label",
                        "rows"=>4,
                        "text"=>"Message *",
                        "line_class"=>"line-ripple",
                    )
      );

// main templates in the /views folder, partials in the /views/partials folder
$m = new Mustache_Engine(array(
    'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__) . '/views'),
    'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__) . '/views/partials'),
));

// loads template from `views/contact.mustache` and renders it.
echo $m->render("contact", $data);

Current results of this script is:

<form id="contact-form" method="post" action="contact.php" role="form">
    <div class="messages"></div>
    <div class="controls">
        <div class="row">
            <div class="col-md-6">
                    <div class="form-group">
                        <label class="floating-label" for="form_name">Firstname *</label>
                        <input type="text" id="form_name" name="name" class="form-control" placeholder="Please enter your firstname *" required='required' data-error="Firstname is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_lastname">Lastname *</label>
                        <input type="text" id="form_lastname" name="surname" class="form-control" placeholder="Please enter your lastname *" required='required' data-error="Lastname is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_email">Email *</label>
                        <input type="email" id="form_email" name="email" class="form-control" placeholder="Please enter your email *" required='required' data-error="Valid email is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_phone">Phone</label>
                        <input type="tel" id="form_phone" name="phone" class="form-control" placeholder="Please enter your phone"  data-error="">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_message">Message *</label>
                        <input type="" id="form_message" name="message" class="form-control" placeholder="Message for me *" required='required' data-error="Please,leave us a message.">
                        <div class="line-ripple"></div>
                    </div>
            </div>
            <div class="col-md-6">
                    <div class="form-group">
                        <label class="floating-label" for="form_name">Firstname *</label>
                        <input type="text" id="form_name" name="name" class="form-control" placeholder="Please enter your firstname *" required='required' data-error="Firstname is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_lastname">Lastname *</label>
                        <input type="text" id="form_lastname" name="surname" class="form-control" placeholder="Please enter your lastname *" required='required' data-error="Lastname is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_email">Email *</label>
                        <input type="email" id="form_email" name="email" class="form-control" placeholder="Please enter your email *" required='required' data-error="Valid email is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_phone">Phone</label>
                        <input type="tel" id="form_phone" name="phone" class="form-control" placeholder="Please enter your phone"  data-error="">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_message">Message *</label>
                        <input type="" id="form_message" name="message" class="form-control" placeholder="Message for me *" required='required' data-error="Please,leave us a message.">
                        <div class="line-ripple"></div>
                    </div>
            </div>
        </div>
        <div class="row">
            <div class="col-md-6">
                    <div class="form-group">
                        <label class="floating-label" for="form_name">Firstname *</label>
                        <input type="text" id="form_name" name="name" class="form-control" placeholder="Please enter your firstname *" required='required' data-error="Firstname is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_lastname">Lastname *</label>
                        <input type="text" id="form_lastname" name="surname" class="form-control" placeholder="Please enter your lastname *" required='required' data-error="Lastname is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_email">Email *</label>
                        <input type="email" id="form_email" name="email" class="form-control" placeholder="Please enter your email *" required='required' data-error="Valid email is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_phone">Phone</label>
                        <input type="tel" id="form_phone" name="phone" class="form-control" placeholder="Please enter your phone"  data-error="">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_message">Message *</label>
                        <input type="" id="form_message" name="message" class="form-control" placeholder="Message for me *" required='required' data-error="Please,leave us a message.">
                        <div class="line-ripple"></div>
                    </div>
            </div>
            <div class="col-md-6">
                    <div class="form-group">
                        <label class="floating-label" for="form_name">Firstname *</label>
                        <input type="text" id="form_name" name="name" class="form-control" placeholder="Please enter your firstname *" required='required' data-error="Firstname is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_lastname">Lastname *</label>
                        <input type="text" id="form_lastname" name="surname" class="form-control" placeholder="Please enter your lastname *" required='required' data-error="Lastname is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_email">Email *</label>
                        <input type="email" id="form_email" name="email" class="form-control" placeholder="Please enter your email *" required='required' data-error="Valid email is required.">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_phone">Phone</label>
                        <input type="tel" id="form_phone" name="phone" class="form-control" placeholder="Please enter your phone"  data-error="">
                        <div class="line-ripple"></div>
                    </div>
                    <div class="form-group">
                        <label class="floating-label" for="form_message">Message *</label>
                        <input type="" id="form_message" name="message" class="form-control" placeholder="Message for me *" required='required' data-error="Please,leave us a message.">
                        <div class="line-ripple"></div>
                    </div>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
            </div>
            <div class="col-md-12">
                <input type="submit" class="btn btn-success btn-send" value="Send message">
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <p class="text-muted"><strong>*</strong> These fields are required.</p>
            </div>
        </div>
    </div>
</form>

Why isn't it doing it correctly?

EDIT Finally got it working, changes are listed below...

Here's contact.mustache

<form id="contact-form" method="post" action="contact.php" role="form">
    <div class="messages"></div>
    <div class="controls">
        {{>input}}
        {{>textarea}}
        <div class="col-md-12">
            <input type="submit" class="btn btn-success btn-send" value="Send message">
        </div>
        <div class="row">
            <div class="col-md-12">
                <p class="text-muted"><strong>*</strong> These fields are required.</p>
            </div>
        </div>
    </div>
</form>

Here's input.mustache

{{#input}}
<div class="row">
    <div class="col-md-6">
        <div class="{{div_class}}">
            <label class="{{label_class}}" for="{{id}}">{{text}}</label>
            <input type="{{type}}" id="{{id}}"    name="{{name}}" class="{{input_class}}" placeholder="{{placeholder}}" {{required}} data-error="{{data-error}}">
            <div class="{{line_class}}"></div>
        </div>
    </div>
</div>
{{/input}}

Here's textarea.mustache

{{#textarea}}
<div class="row">
    <div class="col-md-12">
        <div class="{{div_class}}">
            <label class="{{label_class}}" for="{{id}}">{{text}}</label>
            <textarea id="{{id}}" name="{{name}}" class="{{input_class}}" placeholder="{{placeholder}}" rows="{{rows}}" {{required}} data-error="{{data-error}}"></textarea>
            <div class="{{line_class}}"></div>
        </div>
    </div>
</div>
{{/textarea}}

Here's the data array (code stays same):

$data = array(
    "input"=>array(
                0 =>array(
                    "div_class"=>"form-group", 
                    "id"=>"form_name",
                    "type"=>"text",
                    "name"=>"name",
                    "placeholder"=> "Please enter your firstname *",
                    "required"=>"required='required'",
                    "data-error"=>"Firstname is required.",
                    "input_class"=>"form-control", 
                    "label_class"=>"floating-label",
                    "text"=>"Firstname *",
                    "line_class"=>"line-ripple",
                ),
                1=> array(
                    "div_class"=>"form-group", 
                    "id"=>"form_lastname",
                    "type"=>"text",
                    "name"=>"surname",
                    "placeholder"=> "Please enter your lastname *",
                    "required"=>"required='required'",
                    "data-error"=>"Lastname is required.",
                    "input_class"=>"form-control", 
                    "label_class"=>"floating-label",
                    "text"=>"Lastname *",
                    "line_class"=>"line-ripple",
                ),
                2 =>array(
                    "div_class"=>"form-group", 
                    "id"=>"form_email",
                    "type"=>"email",
                    "name"=>"email",
                    "placeholder"=> "Please enter your email *",
                    "required"=>"required='required'",
                    "data-error"=>"Valid email is required.",
                    "input_class"=>"form-control", 
                    "label_class"=>"floating-label",
                    "text"=>"Email *",
                    "line_class"=>"line-ripple",
                ),
                3 =>array(
                    "div_class"=>"form-group", 
                    "id"=>"form_phone",
                    "type"=>"tel",
                    "name"=>"phone",
                    "placeholder"=> "Please enter your phone",
                    "input_class"=>"form-control", 
                    "label_class"=>"floating-label",
                    "text"=>"Phone",
                    "line_class"=>"line-ripple",
                ),
            ),
"textarea"=>array(
                0 =>array(
                    "div_class"=>"form-group", 
                    "id"=>"form_message",
                    "name"=>"message",
                    "placeholder"=> "Message for me *",
                    "required"=>"required='required'",
                    "data-error"=>"Please,leave us a message.",
                    "input_class"=>"form-control", 
                    "label_class"=>"floating-label",
                    "text"=>"Message *",
                    "rows"=>4,
                    "line_class"=>"line-ripple",
                ),
            )
  );

Here's Output:

<form id="contact-form" method="post" action="contact.php" role="form">
    <div class="messages"></div>
    <div class="controls">
        <div class="row">
            <div class="col-md-6">
                <div class="form-group">
                    <label class="floating-label" for="form_name">Firstname *</label>
                    <input type="text" id="form_name"    name="name" class="form-control" placeholder="Please enter your firstname *" required='required' data-error="Firstname is required.">
                    <div class="line-ripple"></div>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-md-6">
                <div class="form-group">
                    <label class="floating-label" for="form_lastname">Lastname *</label>
                    <input type="text" id="form_lastname"    name="surname" class="form-control" placeholder="Please enter your lastname *" required='required' data-error="Lastname is required.">
                    <div class="line-ripple"></div>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-md-6">
                <div class="form-group">
                    <label class="floating-label" for="form_email">Email *</label>
                    <input type="email" id="form_email"    name="email" class="form-control" placeholder="Please enter your email *" required='required' data-error="Valid email is required.">
                    <div class="line-ripple"></div>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-md-6">
                <div class="form-group">
                    <label class="floating-label" for="form_phone">Phone</label>
                    <input type="tel" id="form_phone"    name="phone" class="form-control" placeholder="Please enter your phone"  data-error="">
                    <div class="line-ripple"></div>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <div class="form-group">
                    <label class="floating-label" for="form_message">Message *</label>
                    <textarea id="form_message" name="message" class="form-control" placeholder="Message for me *" rows="4" required='required' data-error="Please,leave us a message."></textarea>
                    <div class="line-ripple"></div>
                </div>
            </div>
        </div>
        <div class="col-md-12">
            <input type="submit" class="btn btn-success btn-send" value="Send message">
        </div>
        <div class="row">
            <div class="col-md-12">
                <p class="text-muted"><strong>*</strong> These fields are required.</p>
            </div>
        </div>
    </div>
</form>

Solution

  • What actually helped
    The PHP render function seems to only have two parameters, unlike the Javascript one. So removing the third parameter and renaming {{>objPartial}} to {{>input}} so it matches the file should make it work with the PHP renderer.

    Also, each time a partial is encountered in the main template, it will look at the data it's been given and create the code from the partial for each index of the array. The way your code is would work perfectly if each appearance of the partial only rendered for one element of the array.

    At this point, you've very nearly got it working, just need to tweak a couple more things.

    {{#input}}
     <div class="col-md-6">
      <div class="{{div_class}}">
       <label class="{{label_class}}" for="{{id}}">{{text}}</label>
       <input type="{{type}}" id="{{id}}" name="{{name}}" class="{{input_class}}" placeholder="{{placeholder}}" {{required}} data-error="{{data-error}}">
       <div class="{{line_class}}"></div>
      </div>
    {{/input}}
    

    And in the main template just have one reference to {{>input}}.

    <form id="contact-form" method="post" action="contact.php" role="form">
        <div class="messages"></div>
        <div class="controls">
            <div class="row">
               {{>input}}
            </div>
            <div class="row">
                <div class="col-md-12">
                    {{>textarea}}
                </div>
                <div class="col-md-12">
                    <input type="submit" class="btn btn-success btn-send" value="Send message">
                </div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <p class="text-muted"><strong>*</strong> These fields are required.</p>
                </div>
            </div>
        </div>
    </form>
    

    There is a way to retain the format of one row div per two elements, but with bootstrap columns it's not necessary unless you're doing some sort of special formatting.

    Old answer (retained in case it is useful for someone else)
    There's a slight tweak here that I believe will make this work. Rather than calling the partial for each piece of content, call it once for the whole array of content. Your $data array would need to be slightly different, so here's what I'm seeing:

    $data = array(
      "input"=>array(
        array(
          "div_class"=>"text-field", "id"=>"firstName",
          "input_class"=>"text-field__input", "label_class"=>"floating-label",
          "line_class"=>"line-ripple", "text"=>"Curly"
         )
        ),
        array(
           "div_class"=>"text-field", "id"=>"lastName",
           "input_class"=>"text-field__input",
           "label_class"=>"floating-label",
           "line_class"=>"line-ripple", "text"=>"Athos"
        )
      )
    );
    

    And your partial would change slightly to include the .col-md-6:

    {{#input}}
    <div class="col-md-6">
      <div class="{{div_class}}">
        <input type="text" id="{{id}}" class="{{input_class}}">
        <label class="{{label_class}}" for="{{id}}">{{text}}</label>
        <div class="{{line_class}}"></div>
      </div>
    </div>
    {{/input}}
    

    Then you can replace

    <div class="row">
        <div class="col-md-6">
            {{#firstname}}
                {{>objPartial}}
            {{/firstname}}
        </div>
        <div class="col-md-6">
            {{#lastname}}
                {{>objPartial}}
            {{/lastname}}
        </div>
    </div>
    

    with

    <div class="row">
      {{>objPartial}}
    </div>