Passed
Push — master ( 17602b...453007 )
by Chris
04:37
created

Hamle   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 7

Importance

Changes 0
Metric Value
wmc 32
lcom 2
cbo 7
dl 0
loc 181
rs 9.84
c 0
b 0
f 0
1
<?php
2
/*
3
This project is Licenced under The MIT License (MIT)
4
5
Copyright (c) 2014 Christopher Seufert
6
7
Permission is hereby granted, free of charge, to any person obtaining a copy
8
of this software and associated documentation files (the "Software"), to deal
9
in the Software without restriction, including without limitation the rights
10
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
copies of the Software, and to permit persons to whom the Software is
12
furnished to do so, subject to the following conditions:
13
14
The above copyright notice and this permission notice shall be included in
15
all copies or substantial portions of the Software.
16
17
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
THE SOFTWARE.
24
25
 */
26
namespace Seufert\Hamle;
27
/**
28
 * HAMLE - HAML inspired template, with (E)nhancements
29
 *
30
 *
31
 * @author Chris Seufert <[email protected]>
32
 */
33
class Hamle {
34
  /**
35
   * @var Setup instance of hamleSetup Object
36
   */
37
  public $setup;
38
  /**
39
   * @var Hamle Instance of the 'current' hamle Engine
40
   */
41
  static protected $me;
42
  /**
43
   * @var Parse Parser Instance
44
   */
45
  public $parse;
46
  /**
47
   * @var string Filename for Cache file 
48
   */
49
  protected $cacheFile;
50
  /**
51
   * @var bool Enable cacheing of templates
52
   */
53
  protected $cache = true;
54
  /**
55
   * @var array Array of Files required $files[0] is the template file
56
   *            The rest of the files are Snippets 
57
   */
58
  protected $snipFiles;
59
  /**
60
   * @var int Timestamp of latest modification to snipppet file
61
   */
62
  protected $snipMod = 0;
63
64
  public $baseModel;
65
66
  const REL_CHILD = 0x01;  /* Child Relation */
67
  const REL_PARENT = 0x02; /* Parent Relation */
68
  const REL_ANY = 0x03;    /* Unspecified or any relation */
69
  
70
  const SORT_NATURAL = 0x00;    /* Sort in what ever order is 'default' */
71
  const SORT_ASCENDING = 0x02;  /* Sort Ascending */
72
  const SORT_DESCENDING = 0x03; /* Sort Decending */
73
  const SORT_RANDOM = 0x04;     /* Sort Randomly */
74
  /**
75
   * Create new HAMLE Parser
76
   * 
77
   * @param Model $baseModel
78
   * @param Setup $setup
79
   * @throws Exception\Unsupported
80
   * @throws Exception\NotFound
81
   */
82
  function __construct($baseModel, $setup = NULL) {
83
    self::$me = $this;
84
    if(!$setup)
85
      $setup = new Setup();
86
    $this->parse = new Parse();
87
    if(!$setup instanceOf Setup)
88
      throw new Exception\Unsupported("Unsupported Setup Helper was passed, it must extends hamleSetup");
89
    if(!$baseModel instanceOf Model)
90
      throw new Exception\Unsupported("Unsupported Model(".get_class($baseModel).") Type was passed, it must implement hamleModel");
91
    $this->setup = $setup;
92
    $this->baseModel = $baseModel;
93
    $this->initSnipFiles();
94
  }
95
96
  function initSnipFiles() {
97
    if($this->snipMod == 0) {
98
      $this->snipFiles = $this->setup->snippetFiles();
99
      foreach($this->snipFiles as $f) {
100
        if (!file_exists($f)) throw new Exception\NotFound("Unable to find Snippet File ($f)");
101
        $this->snipFiles = max($this->snipFiles, filemtime($f));
102
      }
103
    }
104
  }
105
106
  /**
107
   * Parse a HAMLE Template File
108
   * @param string $hamleFile Template File Name (will have path gathered from hamleSetup->templatePath
109
   * @throws Exception\NotFound If tempalte file cannot be found
110
   * @return Hamle Returns instance for chaining commands
111
   */
112
  function load($hamleFile, \Closure $parseFunc = null) {
113
    $template = $this->setup->templatePath($hamleFile);
114
      if(!file_exists($template)) 
115
        throw new Exception\NotFound("Unable to find HAMLE Template ($template)");
116
    $this->cacheFile = $this->setup->cachePath(
117
                  str_replace("/","-",$hamleFile).".php");
118
    $this->setup->debugLog("Set cache file path to ({$this->cacheFile})");
119
    $cacheFileAge = is_file($this->cacheFile)?filemtime($this->cacheFile):0;
120
    $cacheDirty = !$this->cache ||
121
        $cacheFileAge < $this->snipMod || $cacheFileAge < filemtime($template);
122
    if($cacheDirty) {
123
      $this->setup->debugLog("Parsing File ($template to {$this->cacheFile})");
124
      $this->parse($parseFunc?"":file_get_contents($template), $parseFunc);
125
    } else
126
      $this->setup->debugLog("Using Cached file ({$this->cacheFile})");
127
    return $this;
128
  }
129
  /**
130
   * Parse a HAMLE tempalte from a string 
131
   * _WARNING_ Template Sting will *NOT* be cached, it will be parsed every time
132
   *
133
   * @internal Not for general use, use string($h) instead
134
   * @param string $hamleCode Hamle Template as string
135
   * @throws Exception\ParseError if unable to write to the cache file
136
   */
137
  function parse($hamleCode, \Closure $parseFunc = null) {
138
    if(!$this->cacheFile)
139
        $this->cacheFile = $this->setup->cachePath("string.hamle.php");
140
    if($parseFunc)
141
      $parseFunc($this->parse);
142
    else
143
      $this->parse->str($hamleCode);
144
    $this->setup->debugLog("Loading Snippet Files");
145
    foreach($this->snipFiles as $snip)
146
      $this->parse->parseSnip(file_get_contents($snip));
147
    $this->setup->debugLog("Applying Snippet Files");
148
    $this->parse->applySnip();
149
    $this->setup->debugLog("Executing Parse Filters");
150
    foreach($this->setup->getFilters() as $filter)
151
      $this->parse->parseFilter($filter);
152
    $this->setup->debugLog("Updating Cache File ({$this->cacheFile})");
153
    if(FALSE === file_put_contents($this->cacheFile, $this->parse->output()))
154
      throw new Exception\ParseError(
155
                      "Unable to write to cache file ({$this->cacheFile})");
156
  }
157
158
  /**
159
   * Parse a HAMLE String, and cache output
160
   * @param $hamleString string Hamle
161
   */
162
  function string($hamleString) {
163
    $md5 = md5($hamleString);
164
    $stringId = substr($md5,0,12).substr($md5,24,8);
165
    $this->cacheFile = $this->setup->cachePath("string.$stringId.hamle.php");
166
    if(!is_file($this->cacheFile))
167
      $this->parse($hamleString);
168
  }
169
170
  /**
171
   * Produce HTML Output from hamle Template file
172
   * @return string HTML Output as String
173
   * @throws Exception
174
   */
175
  function output() {
176
    try {
177
      ob_start();
178
      Run::addInstance($this);
179
      $baseModel = $this->baseModel;
180
      $this->baseModel = null;
181
      $currentModel = $baseModel == Scope::getTopScope();
182
      if(!$currentModel && $baseModel) Scope::add($baseModel);
183
      require $this->cacheFile;
184
      if(!$currentModel && $baseModel) Scope::done();
185
      $this->baseModel = $baseModel;
186
      $out = ob_get_contents();
187
      ob_end_clean();
188
    } catch (\Exception $e) {
189
      ob_end_clean();
190
      throw $e;
191
    }
192
    Run::popInstance();
193
    return $out;
194
  }
195
196
  /**
197
   * Get the current line number
198
   * @return int The line number being passed by the parser
199
   */
200
  static function getLineNo() {
201
    if(!isset(self::$me))
202
      return 0;
203
    return self::$me->parse->getLineNo();
204
  }
205
206
  /**
207
   * Disable the caching of hamle templates
208
   */
209
  function disableCache() {
210
    $this->cache = false;
211
  }
212
213
}
214
215