1: <?php
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24: namespace Thelia\Tpex;
25:
26: use Symfony\Component\HttpFoundation\Request;
27: use Symfony\Component\EventDispatcher\EventDispatcherInterface;
28:
29: use Thelia\Tpex\Exception\FileNotFoundException;
30: use Thelia\Tpex\Event\TpexEvent;
31: use Thelia\Tpex\Tokenizer\Tokenize;
32:
33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54:
55:
56: class Tpex
57: {
58: 59: 60: 61: 62: 63:
64: protected $content;
65:
66: 67: 68: 69: 70: 71:
72: protected $basedir;
73:
74: 75: 76: 77:
78: protected $request;
79:
80: 81: 82: 83:
84: protected $dispatcher;
85:
86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101:
102: protected $baseParam = array();
103:
104: protected $init = false;
105:
106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116:
117: protected $config = array(
118: "cacheDir" => false,
119: "cacheTimeFile" => ".time_cache",
120: "fileLifeTime" => 86400,
121: "checkPeriod" => 7200
122: );
123:
124: protected $regex = array(
125: 'include' => '/#INCLUDE[\s]*"([^"]*)"/',
126: 'baseParam' => '/#PARAM_BASE_([a-zA-Z0-9_]+)[\s]*=[\s]*([0-9]*)[\s]*/'
127: );
128:
129: 130: 131:
132: protected $tokenizer;
133:
134: 135: 136: 137: 138: 139:
140: public function __construct(Request $request, EventDispatcherInterface $dispatcher)
141: {
142: $this->request = $request;
143: $this->dispatcher = $dispatcher;
144:
145: $this->tokenizer = new Tokenize($this->request, $this->dispatcher);
146: }
147:
148: 149: 150: 151: 152:
153: public function setContent($content)
154: {
155: $this->content = $content;
156: $this->init = true;
157: }
158:
159: 160: 161: 162: 163:
164: public function setBaseDir($baseDir)
165: {
166: $this->basedir = rtrim($baseDir,"/")."/";
167: }
168:
169: 170: 171: 172:
173: public function configure(array $config)
174: {
175: $this->config = array_merge($this->config, $config);
176:
177: if ($this->config["cacheDir"] !== false) {
178:
179: if (!is_dir($this->config["cacheDir"])) {
180: if (mkdir($this->config["cacheDir"], 0777, true) === false) {
181: throw new \RuntimeException(sprintf("%s directory does not exists and it is impossible to create it", $this->cacheDir));
182: }
183:
184: if (file_exists($this->config["cacheDir"] . '/' . $this->config["cacheTimeFile"])) {
185: file_put_contents($this->config["cacheDir"] . '/' . $this->config["cacheTimeFile"], time());
186: }
187: }
188: }
189: }
190:
191: 192: 193: 194: 195: 196:
197: public function isInitialized()
198: {
199: return $this->init;
200: }
201:
202: 203: 204: 205: 206: 207:
208: public function getContent()
209: {
210: return $this->content;
211: }
212:
213: public function setLoop(array $loop)
214: {
215: $this->tokenizer->setLoop($loop);
216: }
217:
218: public function setFilter(array $filter)
219: {
220: $this->tokenizer->setFilter($filter);
221: }
222:
223: public function setTestLoop(array $testLoop)
224: {
225: $this->tokenizer->setTestLoop($testLoop);
226: }
227:
228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243:
244: public function setBaseParams(array $baseParams)
245: {
246: foreach ($baseParams as $name => $className) {
247: $this->addBaseParam($name, $className);
248: }
249: }
250:
251: 252: 253: 254: 255: 256: 257: 258:
259: public function addBaseParam($name, $className)
260: {
261: if (array_key_exists($name, $this->baseParam)) {
262: throw new \InvalidArgumentException(sprintf("%s baseParam name already exists for %s class name", $name, $className));
263: }
264:
265: $this->baseParam[$name] = $className;
266: }
267:
268: public function execute()
269: {
270: if ($this->isInitialized() === false) {
271: throw new \RuntimeException("Tpex must be initialize before executing. See Thelia\Tpex\Tpex::init() for more information");
272: }
273:
274: $this->parseBaseParam();
275:
276: $substitEvent = new TpexEvent($this->getContent(), $this->request);
277: $this->dispatcher->dispatch(TpexEvents::SUBSTITUTION, $substitEvent);
278:
279: $this->content = $substitEvent->getContent();
280:
281: $this->parseInclude();
282:
283:
284: $this->config["cacheDir"] ? $this->parseStringWithCache() : $this->parseString();
285:
286: return $this->content;
287: }
288:
289: protected function parseBaseParam()
290: {
291: if (preg_match_all($this->regex['baseParam'], $this->content, $matches, PREG_SET_ORDER)) {
292: foreach ($matches as $match) {
293: if (array_key_exists($match[1], $this->baseParam)) {
294: $class = $this->baseParam[$match[1]];
295: $obj = new $class($this->request, $match[2]);
296: $obj->exec();
297: } else {
298: throw new \RuntimeException(sprintf("baseParam %s is not define", $match[1]));
299: }
300: }
301:
302: $this->content = str_replace($match[0], "", $this->content);
303: }
304:
305: }
306:
307: protected function parseInclude()
308: {
309: if (preg_match_all($this->regex["include"], $this->content, $matches, PREG_SET_ORDER)) {
310: foreach ($matches as $match) {
311: $file = $this->basedir . $match[1];
312:
313: if (file_exists($file)) {
314: $content = file_get_contents($file);
315:
316: if ($content !== false) {
317:
318: $this->content = str_replace($match[0], $content, $this->content);
319:
320: $this->parseInclude();
321: }
322: } else {
323: throw new FileNotFoundException(sprintf("%s not found in %s directory", $match[1], $this->basedir));
324: }
325: }
326: }
327: }
328:
329: protected function parseString()
330: {
331: $this->tokenizer->setContent($this->content);
332:
333: $compile = $this->tokenizer->tokenize();
334:
335: $this->content = $compile->exec();
336:
337: }
338:
339: protected function parseStringWithCache()
340: {
341: $this->cleanCache();
342: $fileCache = $this->config["cacheDir"] . '/' . md5($this->content) . ".cache";
343:
344: if (file_exists($fileCache)) {
345:
346: @touch($fileCache);
347: $this->content = unserialize(file_get_contents($fileCache));
348: } else {
349: $this->parseString();
350: file_put_contents($fileCache, $this->content);
351: }
352: }
353:
354: protected function cleanCache()
355: {
356: $lastCheck = file_get_contents($this->config["cacheDir"] . "/" . $this->config["cacheTimeFile"]);
357:
358: if(time() - $lastCheck < $this->config["checkPeriod"]) return;
359:
360: file_put_contents($this->config["cacheDir"] . "/" . $this->config["cacheTimeFile"], time());
361:
362: if ($dh = @opendir($this->config["cacheDir"])) {
363: while ($file = @readdir($dh)) {
364: if (strstr($file, '.cache') !== false) {
365: $filemtime = @filemtime($this->config["cacheDir"] . '/' . $file);
366:
367: if (! $filemtime || (time() - $filemtime) >= $this->config["fileLifetime"] ) {
368: @unlink($this->config["cacheDir"] . '/' . $file);
369: }
370: }
371: }
372: }
373: }
374: }
375: