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: use Psr\Log\LoggerInterface;
29:
30: use Thelia\Tpex\Exception\FileNotFoundException;
31:
32: /**
33: *
34: * Tpex is a parser used by Thelia CMS (http://thelia.net)
35: *
36: * Tpex use syntax like loop :
37: * <THELIA_name type="loopName" parameter1="value1" parameter2="value2">
38: * #SUBTITUTION1 #SUBSTITUTION2 #SUBSTITUTION-n
39: * </THELIA_name>
40: *
41: * you have to implements your own loop, all the logical is in your loop not in Tpex
42: *
43: * filter syntax :
44: *
45: * [...(filter_name{param1, param2, ... } ... ]
46: *
47: * base param syntax :
48: *
49: * PARAM_BASE_parameName=paramValue
50: *
51: *
52: * @author Manuel Raynaud <mraynaud@openstudio.fr>
53: */
54:
55: class Tpex
56: {
57: /**
58: *
59: * $content contains string to parse
60: *
61: * @var string
62: */
63: protected $content;
64:
65: /**
66: *
67: * the base directory for searching all files for inclusion
68: *
69: * @var string
70: */
71: protected $basedir;
72:
73: /**
74: *
75: * @var Symfony\Component\HttpFoundation\Request
76: */
77: protected $request;
78:
79: /**
80: *
81: * @var Psr\Log\LoggerInterface
82: */
83: protected $logger;
84:
85: /**
86: *
87: * @var Symfony\Component\EventDispatcher\EventDispatcherInterface
88: */
89: protected $dispatcher;
90:
91: /**
92: * associative array containing information for loop execution
93: *
94: * key is loop name
95: * value is the class implementing/extending base loop classes
96: *
97: * ex :
98: *
99: * $loop = array(
100: * "product" => "Thelia\Loop\Product",
101: * "category" => "Thelia\Loop\Category",
102: * "myLoop" => "My\Own\Loop"
103: * );
104: *
105: * @var Array
106: */
107: protected $loop = array();
108:
109: /**
110: * associative array containing information for filter execution
111: *
112: * key is filter name
113: * value is the class implementing/extending base loop classes
114: *
115: * ex :
116: *
117: * $filter = array(
118: * "upperCase" => "Thelia\Filter\UpperCase",
119: * "lowerCase" => "Thelia\Filter\LowerCase",
120: * "myFilter" => "My\Own\Filter"
121: * );
122: *
123: * @var Array
124: */
125: protected $filter = array();
126:
127: /**
128: * associative array containing information for baseParam execution
129: *
130: * key is baseParam name
131: * value is the class implementing/extending base baseParam classes
132: *
133: * ex :
134: *
135: * $baseParam = array(
136: * "secure" => "Thelia\BaseParam\Secure",
137: * "reset" => "Thelia\BaseParam\reset",
138: * "myBaseParam" => "My\Own\BaseParam"
139: * );
140: *
141: * @var Array
142: */
143: protected $baseParam = array();
144:
145: protected $substitution;
146:
147: protected $init;
148:
149: /**
150: *
151: * @param \Symfony\Component\HttpFoundation\Request $request Request object containing current http request
152: * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher for dispatching Tpex event like substitute or include
153: * @param string $content the content to parse
154: * @param string $basedir where files are located
155: */
156: public function init(Request $request, EventDispatcherInterface $dispatcher, $content, $basedir)
157: {
158: $this->request = $request;
159: $this->dispatcher = $dispatcher;
160: $this->content = $content;
161: $this->basedir = rtrim($basedir,"/")."/";
162:
163: $this->init = true;
164: }
165:
166: public function configure(array $loops = array(), array $filters = array(), array $baseParams = array())
167: {
168: $this->addLoops($loops);
169: $this->addFilters($filters);
170: $this->addBaseParams($baseParams);
171: }
172:
173: /**
174: *
175: * @param \Psr\Log\LoggerInterface $logger logger implementing LoggerInterface like Tlog
176: */
177: public function setLogger(LoggerInterface $logger)
178: {
179: $this->logger = $logger;
180: }
181:
182: /**
183: *
184: * add multiple loops in one time in Tpex parser
185: *
186: * array key contains loop name
187: * array value contain className to execute for rendering this loop
188: *
189: * $loops = array(
190: * "product" => "Thelia\Loop\Product",
191: * "category" => "Thelia\Loop\Category",
192: * "myLoop" => "My\Own\Loop"
193: * );
194: *
195: * @param array $loops
196: * @throws \InvalidArgumentException
197: */
198: public function addLoops(array $loops)
199: {
200: $this->addProperties("loop", $loops);
201: }
202:
203: /**
204: *
205: * add a new loop to Tpex parser
206: *
207: * @param string $name loop name. Must be unique
208: * @param type $className class name implementing/extending loop classes
209: * @throws \InvalidArgumentException
210: */
211: public function addLoop($name, $className)
212: {
213: $this->addProperty("loop", $name, $className);
214: }
215:
216: /**
217: *
218: * add multiple filters in one time in Tpex parser
219: *
220: * key is filter name, must be unique
221: * value is the class implementing/extending base loop classes
222: *
223: * $filter = array(
224: * "upperCase" => "Thelia\Filter\UpperCase",
225: * "lowerCase" => "Thelia\Filter\LowerCase",
226: * "myFilter" => "My\Own\Filter"
227: * );
228: *
229: * @param array $filters
230: * @throws \InvalidArgumentException
231: */
232: public function addFilters(array $filters)
233: {
234: $this->addProperties("filter", $filters);
235: }
236:
237: /**
238: *
239: * add a new filter to Tpex parser
240: *
241: * @param string $name filter name. Must be unique
242: * @param type $className class name implementing/extending filter classes
243: * @throws \InvalidArgumentException
244: */
245: public function addFilter($name, $className)
246: {
247: $this->addProperty("filter", $name, $className);
248: }
249:
250: /**
251: *
252: * add multiple baseParam ine one time in Tpex Parser
253: *
254: * key is baseParam name
255: * value is the class implementing/extending base baseParam classes
256: *
257: * $baseParam = array(
258: * "secure" => "Thelia\BaseParam\Secure",
259: * "reset" => "Thelia\BaseParam\reset",
260: * "myBaseParam" => "My\Own\BaseParam"
261: * );
262: *
263: * @param array $baseParams
264: * @throws \InvalidArgumentException
265: */
266: public function addBaseParams(array $baseParams)
267: {
268: $this->addProperties("baseParam", $baseParams);
269: }
270:
271: /**
272: *
273: * add a new baseParam to Tpex param
274: *
275: * @param type $name baseParam name. Must be unique
276: * @param type $className class name implementing/extending filter classes
277: * @throws \InvalidArgumentException
278: */
279: public function addBaseParam($name, $className)
280: {
281: $this->addProperty("baseParam", $name, $className);
282: }
283:
284: protected function addProperties($property, array $parameters)
285: {
286: foreach ($parameters as $name => $className) {
287: $this->addProperty($property, $name, $className);
288: }
289: }
290:
291: protected function addProperty($property, $name, $className)
292: {
293: if (!isset($this->$property)) {
294: throw new \InvalidArgumentException(sprintf("%s property does not exists in Tpex class", $property));
295: }
296:
297: if (!array_key_exists($name, $this->$property)) {
298: $this->$property = array_merge($this->$property, array($name => $className));
299: } else {
300: throw new \InvalidArgumentException(sprintf("%s %s name already exists for %s class name", $name, $property, $className));
301: }
302: }
303:
304: public function execute()
305: {
306: if (true !== $this->init) {
307: throw new \RuntimeException("Tpex must be initialize before executing. See Thelia\Tpex\Tpex::init() for more information");
308: }
309:
310: $this->parseBaseParam();
311:
312: $this->parseInclude();
313:
314: return $this->content;
315: }
316:
317: protected function parseBaseParam()
318: {
319: if (preg_match_all("/#PARAM_BASE_([a-zA-Z0-9_]+)[\s]*=[\s]*([0-9]*)[\s]*/", $this->content, $matches, PREG_SET_ORDER)) {
320:
321: }
322: }
323:
324: protected function parseInclude()
325: {
326: if (preg_match_all('/#INCLUDE[\s]*"([^"]*)"/', $this->content, $matches, PREG_SET_ORDER)) {
327: foreach ($matches as $match) {
328: $file = $this->basedir . $match[1];
329:
330: if (file_exists($file)) {
331: $content = file_get_contents($file);
332:
333: if ($content !== false) {
334:
335: $this->content = str_replace($match[0], $content, $this->content);
336:
337: $this->parseInclude();
338: }
339: } else {
340: throw new FileNotFoundException(sprintf("%s not found in %s directory", $match[1], $this->basedir));
341: }
342: }
343: }
344: }
345:
346: }
347: