Overview

Namespaces

  • Thelia
    • Action
    • Config
    • Controller
    • Core
      • Bundle
      • DependencyInjection
        • Compiler
        • Loader
      • Event
      • EventListener
      • Template
        • BaseParam
    • Exception
    • Log
      • Destination
    • Model
      • map
      • om
    • Routing
      • Matcher
    • Tools
    • Tpex
      • BaseParam
      • Element
        • Loop
        • TestLoop
      • Event
      • Exception
      • Filter
      • Tokenizer

Classes

  • Tools
  • Tpex
  • TpexEvents
  • TpexToken
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: /*************************************************************************************/
  3: /*                                                                                   */
  4: /*      Thelia                                                                       */
  5: /*                                                                                   */
  6: /*      Copyright (c) OpenStudio                                                     */
  7: /*  email : info@thelia.net                                                      */
  8: /*      web : http://www.thelia.net                                                  */
  9: /*                                                                                   */
 10: /*      This program is free software; you can redistribute it and/or modify         */
 11: /*      it under the terms of the GNU General Public License as published by         */
 12: /*      the Free Software Foundation; either version 3 of the License                */
 13: /*                                                                                   */
 14: /*      This program is distributed in the hope that it will be useful,              */
 15: /*      but WITHOUT ANY WARRANTY; without even the implied warranty of               */
 16: /*      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                */
 17: /*      GNU General Public License for more details.                                 */
 18: /*                                                                                   */
 19: /*      You should have received a copy of the GNU General Public License            */
 20: /*      along with this program. If not, see <http://www.gnu.org/licenses/>.     */
 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:  * Tpex is a parser used by Thelia CMS (http://thelia.net)
 36:  *
 37:  * Tpex use syntax like loop :
 38:  * <THELIA id="loopId" type="loopName" parameter1="value1" parameter2="value2">
 39:  *      #SUBTITUTION1 #SUBSTITUTION2 #SUBSTITUTION-n
 40:  * </THELIA>
 41:  *
 42:  * you have to implements your own loop, all the logical is in your loop not in Tpex
 43:  *
 44:  * filter syntax :
 45:  *
 46:  * [...(filter_name{param1, param2, ... }) ... ]
 47:  *
 48:  * base param syntax :
 49:  *
 50:  * PARAM_BASE_parameName=paramValue
 51:  *
 52:  *
 53:  * @author Manuel Raynaud <mraynaud@openstudio.fr>
 54:  */
 55: 
 56: class Tpex
 57: {
 58:     /**
 59:      *
 60:      * $content contains string to parse
 61:      *
 62:      * @var string
 63:      */
 64:     protected $content;
 65: 
 66:     /**
 67:      *
 68:      * the base directory for searching all files for inclusion
 69:      *
 70:      * @var string
 71:      */
 72:     protected $basedir;
 73: 
 74:     /**
 75:      *
 76:      * @var \Symfony\Component\HttpFoundation\Request
 77:      */
 78:     protected $request;
 79: 
 80:     /**
 81:      *
 82:      * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
 83:      */
 84:     protected $dispatcher;
 85: 
 86:     /**
 87:      * associative array containing information for baseParam execution
 88:      *
 89:      * key is baseParam name
 90:      * value is the class implementing/extending base baseParam classes
 91:      *
 92:      * ex :
 93:      *
 94:      * $baseParam = array(
 95:      *  "secure" => "Thelia\BaseParam\Secure",
 96:      *  "reset" => "Thelia\BaseParam\reset",
 97:      *  "myBaseParam" => "My\Own\BaseParam"
 98:      * );
 99:      *
100:      * @var Array
101:      */
102:     protected $baseParam = array();
103: 
104:     protected $init = false;
105: 
106:     /**
107:      *
108:      * config array
109:      *
110:      * cacheDir where cache is created
111:      * cacheTimeFile File containing last cache pass
112:      * fileLifeTime : file lifetime in seconds in cache system
113:      * checkPeriod : Time in seconds between each cache examination
114:      *
115:      * @var array
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:      * @var \Thelia\Tpex\Tokenizer\Tokenize
131:      */
132:     protected $tokenizer;
133: 
134:     /**
135:      * Tpex constructor
136:      *
137:      * @param \Symfony\Component\HttpFoundation\Request $request
138:      * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
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:      * set the content to parse
150:      *
151:      * @param string $content
152:      */
153:     public function setContent($content)
154:     {
155:         $this->content = $content;
156:         $this->init = true;
157:     }
158: 
159:     /**
160:      * set the base directory. include are based from this base directory
161:      *
162:      * @param string $baseDir
163:      */
164:     public function setBaseDir($baseDir)
165:     {
166:         $this->basedir = rtrim($baseDir,"/")."/";
167:     }
168: 
169:     /**
170:      * @param array $config
171:      * @throws \RuntimeException
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:      * verify if Tpex is initialized
194:      *
195:      * @return boolean
196:      */
197:     public function isInitialized()
198:     {
199:         return $this->init;
200:     }
201: 
202:     /**
203:      *
204:      * return the current at the current state during parsing
205:      *
206:      * @return string
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:      * add multiple baseParam ine one time in Tpex Parser
231:      *
232:      * key is baseParam name
233:      * value is the class implementing/extending base baseParam classes
234:      *
235:      * $baseParam = array(
236:      *  "secure" => "Thelia\BaseParam\Secure",
237:      *  "reset" => "Thelia\BaseParam\reset",
238:      *  "myBaseParam" => "My\Own\BaseParam"
239:      * );
240:      *
241:      * @param  array                     $baseParams
242:      * @throws \InvalidArgumentException
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:      * add a new baseParam to Tpex param
254:      *
255:      * @param  type                      $name      baseParam name. Must be unique
256:      * @param  type                      $className class name implementing/extending filter classes
257:      * @throws \InvalidArgumentException
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:         //Now we can parse content
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: 
thelia API documentation generated by ApiGen 2.8.0