Skip to content

Instantly share code, notes, and snippets.

@bobthecow
Created December 6, 2012 23:31
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save bobthecow/61161639d8be82a75b5e to your computer and use it in GitHub Desktop.
Using a "real ViewModel" with Mustache
{
"require": {
"mustache/mustache": "*"
},
"autoload": {
"classmap": ["IteratorPresenter.php", "PostViewModel.php"]
}
}
<?php
require 'vendor/autoload.php';
$mustache = new Mustache_Engine(array(
'loader' => new Mustache_Loader_FilesystemLoader(__DIR__),
));
// if this was real, you'd gather up some datas, but this'll do for us ...
$title = 'Hello World';
$createdAt = new DateTime('yesterday');
$tags = array('Lorem', 'Ipsum', 'Dolor');
$content = <<<EOS
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum.
Massa justo sit amet risus. Sed posuere consectetur est at lobortis.
EOS;
// now prepare your view model
$viewModel = new PostViewModel($title, $content, $createdAt, $tags);
// you prolly want to do more with this than just echo, but here it is:
echo $mustache->render('post', $viewModel);
<?php
class IteratorPresenter implements IteratorAggregate
{
private $values;
public function __construct($values)
{
if (!is_array($values) && !$values instanceof Traversable) {
throw new InvalidArgumentException('IteratorPresenter requires an array or Traversable object');
}
$this->values = $values;
}
public function getIterator()
{
$values = array();
foreach ($this->values as $key => $val) {
$values[$key] = array(
'key' => $key,
'value' => $val,
'first' => false,
'last' => false,
);
}
$keys = array_keys($values);
if (!empty($keys)) {
$values[reset($keys)]['first'] = true;
$values[end($keys)]['last'] = true;
}
return new ArrayIterator($values);
}
}
<article>
<h1>{{ title }}</h1>
<section class="content">
{{{ content }}}
</section>
<aside class="meta">
Published on <time data-timestamp="{{ timestamp }}">{{ createdAt }}</time>.
{{# hasTags }}
Tagged as:
{{# tags }}
<a href="/tag/{{ value }}">{{ value }}</a>{{^ last }}, {{/ last }}
{{/ tags }}
{{/ hasTags }}
</aside>
</article>
<?php
class PostViewModel
{
private $title;
private $rawContent;
private $content;
private $tags;
// Our constructor takes property primitives. In Real Life, this would most likely
// take a domain model or two, e.g.:
//
// public function __construct(BlogPost $post) ...
//
// ... but that's beyond the scope of this gist :)
public function __construct($title, $content, DateTime $createdAt, array $tags)
{
$this->title = $title;
$this->rawContent = $content;
$this->createdAt = $createdAt;
$this->tags = $tags;
}
public function content()
{
if (!isset($this->content)) {
// in real life this would be Markdown processing, or something way more
// awesome than nl2br :)
$this->content = nl2br($this->rawContent);
}
return $this->content;
}
public function title()
{
return empty($this->title) ? 'Untitled' : $this->title;
}
public function timestamp()
{
return $this->createdAt->getTimestamp();
}
public function createdAt()
{
return $this->createdAt->format("F j, Y, g:i a");
}
public function hasTags()
{
return !empty($this->tags);
}
public function tags()
{
return new IteratorPresenter($this->tags);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment