Platform  3.1
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.Layout.php
Go to the documentation of this file.
1 <?php
2 /*
3  * @author Anakeen
4  * @license http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ Anakeen - licence CC
5  * @package FDL
6 */
7 /**
8  * Layout Class
9  *
10  * @author Anakeen 2000
11  * @version $Id: Class.Layout.php,v 1.49 2009/01/14 14:48:14 eric Exp $
12  * @license http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ Anakeen - licence CC
13  * @package FDL
14  * @subpackage CORE
15  */
16 /**
17  */
18 //
19 // PHP Layout Class
20 // this class is designed to perform the final page layout of
21 // an application.
22 // this class uses a template with three dynamic zones header,toc and main
23 // doc.
24 //
25 //
26 // Layout Class can manage three kind of datas :
27 //
28 // 1) Simple tags :
29 // those tags are enclosed into brackets [] and can be replaced with any
30 // dynamic data given with the Set method.
31 // e.g : [MYDATA] => $this->Set("MYDATA","this is my text");
32 //
33 // 2) Block of Data :
34 // those tags are used to manage repeated set of data (as table for instance)
35 // You can assign a table of data to a specific block.
36 // e.g : $table = array ( "0" => array ( "name" => "John",
37 // "surname" => "Smith"),
38 // "1" => array ( "name" => "Robert",
39 // "surname" => "Martin"));
40 //
41 // the block : [BLOCK IDENTITY]
42 // <tr><td align="left">[NAME]</td>
43 // <td align="right">[SURNAME]</td>
44 // </tr>
45 // [ENDBLOCK IDENTITY]
46 //
47 // the code : $lay = new Layout ("file containing the block");
48 // $lay->SetBlockCorresp("IDENTITY","NAME","name");
49 // $lay->SetBlockCorresp("IDENTITY","SURNAME","surname");
50 // $lay->SetBlockData("IDENTITY",$table);
51 //
52 // $out = $lay->gen();
53 //
54 // $out : <tr><td align="left">John</td>
55 // <td align="right">Smith</td>
56 // </tr>
57 // <tr><td align="left">Robert</td>
58 // <td align="right">Martin</td>
59 // </tr>
60 //
61 // 3) Call a specific script (need Core App Environment to work)
62 // tag syntax : [ZONE zonename]
63 //
64 // the zone name is linked to a specific application/function
65 //
66 // eg : [ZONE CORE:APPLIST]
67 //
68 // then the APPLIST function in the CORE Application is called
69 // this function can then use another layout etc......
70 //
71 //
72 // Copyright (c) 1999 Anakeen S.A.
73 // Yannick Le Briquer
74 //
75 // $Id: Class.Layout.php,v 1.49 2009/01/14 14:48:14 eric Exp $
77 include_once ('Class.Log.php');
78 include_once ('Class.Action.php');
79 include_once ('Class.Application.php');
80 
81 class Layout
82 {
83  //############################################
84  //#
85  private $strip = 'Y';
86  public $encoding = "";
87  public $noparse = false; // return template without parse
88 
89  /**
90  * @var array different par of original zone
91  */
92  private $zone;
93  //########################################################################
94  //# Public methods
95  //#
96  //#
97 
98 
99  /**
100  * construct layout for view card containt
101  *
102  * @param string $caneva file of the template
103  * @param Action $action current action
104  * @param string $template default template
105  */
106  function Layout($caneva = "", $action = "", $template = "[OUT]")
107  {
108  $this->LOG = new Log("", "Layout");
109  if (($template == "[OUT]") && ($caneva != "")) $this->template = sprintf(_("Template [%s] not found") , $caneva);
110  else $this->template = $template;
111  $this->action = & $action;
112  $this->generation = "";
113  $file = $caneva;
114  $this->file = "";
115  if ($caneva != "") {
116  if ((!file_exists($file)) && ($file[0] != '/')) {
117  $file = GetParam("CORE_PUBDIR") . "/$file"; // try absolute
118 
119  }
120  if (file_exists($file)) {
121  $this->file = $file;
122  $this->template = file_get_contents($file);
123  }
124  }
125  }
126  /**
127  * return original zone
128  * @param string $key
129  */
130  function getZone($key = '')
131  {
132  if ($key) {
133  if (isset($this->zone[$key])) return $this->zone[$key];
134  return null;
135  } else {
136  return $this->zone;
137  }
138  }
139 
140  function setZone($zone)
141  {
142  $this->zone = $zone;
143  }
144  function SetBlockCorresp($p_nom_block, $p_nom_modele, $p_nom = NULL)
145  {
146  $this->corresp["$p_nom_block"]["[$p_nom_modele]"] = ($p_nom == NULL ? $p_nom_modele : "$p_nom");
147  }
148 
149  function SetBlockData($p_nom_block, $data = NULL)
150  {
151  $this->data["$p_nom_block"] = $data;
152  // affect the corresp block if not
153  if (is_array($data)) {
154  reset($data);
155  $elem = pos($data);
156  if (isset($elem) && is_array($elem)) {
157  reset($elem);
158  while (list($k, $v) = each($elem)) {
159  if (!isset($this->corresp["$p_nom_block"]["[$k]"])) {
160  $this->SetBlockCorresp($p_nom_block, $k);
161  }
162  }
163  }
164  }
165  }
166 
167  function GetBlockData($p_nom_block)
168  {
169  if (isset($this->data["$p_nom_block"])) return $this->data["$p_nom_block"];
170  return false;
171  }
172  function SetBlock($name, $block)
173  {
174  if ($this->strip == 'Y') {
175  // $block = StripSlashes($block);
176  $block = str_replace("\\\"", "\"", $block);
177  }
178  $out = "";
179 
180  if (isset($this->data) && isset($this->data["$name"]) && is_array($this->data["$name"])) {
181  foreach ($this->data["$name"] as $k => $v) {
182  $loc = $block;
183  if (!is_array($this->corresp["$name"])) return sprintf(_("SetBlock:error [%s]") , $name);
184  foreach ($this->corresp["$name"] as $k2 => $v2) {
185  if ((!is_object($v[$v2])) && (!is_array($v[$v2]))) $loc = str_replace($k2, $v[$v2], $loc);
186  }
187  $this->rif = & $v;
188  $this->ParseIf($loc);
189  $out.= $loc;
190  }
191  }
192  $this->ParseBlock($out);
193  return ($out);
194  }
195 
196  function ParseBlock(&$out)
197  {
198  $out = preg_replace("/(?m)\[BLOCK\s*([^\]]*)\](.*?)\[ENDBLOCK\s*\\1\]/se", "\$this->SetBlock('\\1','\\2')", $out);
199  }
200 
201  function TestIf($name, $block, $not = false)
202  {
203  $out = "";
204  if (array_key_exists($name, $this->rif) || isset($this->rkey[$name])) {
205  $n = (array_key_exists($name, $this->rif)) ? $this->rif[$name] : $this->rkey[$name];
206  if ($n xor $not) {
207  if ($this->strip == 'Y') {
208  $block = str_replace("\\\"", "\"", $block);
209  }
210  $out = $block;
211  $this->ParseBlock($out);
212  $this->ParseIf($out);
213  }
214  } else {
215  if ($this->strip == 'Y') $block = str_replace("\\\"", "\"", $block);
216 
217  if ($not) $out = "[IFNOT $name]" . $block . "[ENDIF $name]";
218  else $out = "[IF $name]" . $block . "[ENDIF $name]";
219  }
220  return ($out);
221  }
222  function ParseIf(&$out)
223  {
224  $out = preg_replace("/(?m)\[IF(NOT)?\s+([^\]]*)\](.*?)\[ENDIF\s*\\2\]/se", "\$this->TestIf('\\2','\\3','\\1')", $out);
225  }
226 
227  function ParseZone(&$out)
228  {
229  $out = preg_replace("/\[ZONE\s+([^:]*):([^\]]*)\]/e", "\$this->execute('\\1','\\2')", $out);
230  }
231 
232  function ParseKey(&$out)
233  {
234  if (isset($this->rkey)) {
235  $out = str_replace($this->pkey, $this->rkey, $out);
236  }
237  }
238  /**
239  * define new encoding text
240  * default is iso8859-1
241  */
242  function setEncoding($enc)
243  {
244  if ($enc == "utf-8") {
245  $this->encoding = $enc;
246  // bind_textdomain_codeset("what", 'UTF-8');
247 
248  }
249  }
250 
251  function execute($appname, $actionargn)
252  {
253  $limit = getParam('CORE_LAYOUT_EXECUTE_RECURSION_LIMIT', 0);
254  if (is_numeric($limit) && $limit > 0) {
255  $loop = $this->getRecursionCount(__CLASS__, __FUNCTION__);
256  if ($loop['count'] >= $limit) {
257  $this->printRecursionCountError(__CLASS__, __FUNCTION__, $loop['count']);
258  }
259  }
260 
261  if ($this->action == "") return ("Layout not used in a core environment");
262  // analyse action & its args
263  $actionargn = str_replace(":", "--", $actionargn); //For buggy function parse_url in PHP 4.3.1
264  $acturl = parse_url($actionargn);
265  $actionname = $acturl["path"];
266 
267  global $ZONE_ARGS;
268  $OLD_ZONE_ARGS = $ZONE_ARGS;
269  if (isset($acturl["query"])) {
270  $acturl["query"] = str_replace("--", ":", $acturl["query"]); //For buggy function parse_url in PHP 4.3.1
271  $zargs = explode("&", $acturl["query"]);
272  while (list($k, $v) = each($zargs)) {
273  if (preg_match("/([^=]*)=(.*)/", $v, $regs)) {
274  // memo zone args for next action execute
275  $ZONE_ARGS[$regs[1]] = urldecode($regs[2]);
276  }
277  }
278  }
279 
280  if ($appname != $this->action->parent->name) {
281  $appl = new Application();
282  $appl->Set($appname, $this->action->parent);
283  } else {
284  $appl = & $this->action->parent;
285  }
286 
287  if (($actionname != $this->action->name) || ($OLD_ZONE_ARGS != $ZONE_ARGS)) {
288  $act = new Action();
289 
290  if ($act->Exists($actionname, $appl->id)) {
291 
292  $res = $act->Set($actionname, $appl);
293  } else {
294  // it's a no-action zone (no ACL, cannot be call directly by URL)
295  $act->name = $actionname;
296 
297  $res = $act->CompleteSet($appl);
298  }
299  if ($res == "") {
300  $res = $act->execute();
301  }
302  $ZONE_ARGS = $OLD_ZONE_ARGS; // restore old zone args
303  return ($res);
304  } else {
305  return ("Fatal loop : $actionname is called in $actionname");
306  }
307  }
308 
309  function set($tag, $val)
310  {
311  $this->pkey[$tag] = "[$tag]";
312  $this->rkey[$tag] = $val;
313  }
314 
315  function get($tag)
316  {
317  if (isset($this->rkey)) return $this->rkey[$tag];
318  return "";
319  }
320 
321  function ParseRef(&$out)
322  {
323 
324  $out = preg_replace("/\[IMG:([^\|\]]+)\|([0-9]+)\]/e", "\$this->action->GetImageUrl('\\1',true,'\\2')", $out);
325 
326  $out = preg_replace("/\[IMG:([^\]\|]+)\]/e", "\$this->action->GetImageUrl('\\1')", $out);
327 
328  $out = preg_replace("/\[IMGF:([^\]]*)\]/e", "\$this->action->GetFilteredImageUrl('\\1')", $out);
329 
330  $out = preg_replace("/\[SCRIPT:([^\]]*)\]/e", "\$this->action->GetScriptUrl('\\1')", $out);
331  }
332 
333  protected function ParseText(&$out)
334  {
335 
336  $out = preg_replace("/\[TEXT:([^\]]*)\]/e", "\$this->Text('\\1')", $out);
337  }
338  function Text($s)
339  {
340  if ($s == "") return $s;
341  return _($s);
342  }
343 
344  function GenJsRef()
345  {
346  $js = "";
347  $list[] = $this->action->GetParam("CORE_JSURL") . "/logmsg.js?wv=" . $this->action->GetParam("WVERSION");
348  $list = array_merge($list, $this->action->parent->GetJsRef());
349 
350  reset($list);
351  while (list($k, $v) = each($list)) {
352  $js.= "<script type=\"text/javascript\" language=\"JavaScript\" src=\"$v\"></script>\n";
353  }
354  return $js;
355  }
356 
357  function GenJsCode($showlog, $onlylog = false)
358  {
359  $out = "";
360  if (!$onlylog) {
361  $list = $this->action->parent->GetJsCode();
362  foreach ($list as $k => $v) {
363  $out.= $v . "\n";
364  }
365  }
366  if ($showlog) {
367  // Add log messages
368  $list = $this->action->parent->GetLogMsg();
369  reset($list);
370  $out.= "var logmsg=new Array();\n";
371  while (list($k, $v) = each($list)) {
372  if (($v[0] == '{')) $out.= "logmsg[$k]=$v;\n";
373  else $out.= "logmsg[$k]=" . json_encode($v) . ";\n";
374  }
375 
376  $out.= "if ('displayLogMsg' in window) displayLogMsg(logmsg);\n";
377  $this->action->parent->ClearLogMsg();
378  // Add warning messages
379  $list = $this->action->parent->GetWarningMsg();
380  if (count($list) > 0) $out.= "displayWarningMsg('" . implode("\\n---------\\n", $list) . "');\n";
381  $this->action->parent->ClearWarningMsg();
382  }
383  if (!$onlylog) {
384  // Add action notification messages
385  $this->action->getActionDone($actcode, $actarg);
386  if (count($actcode) > 0) {
387  $out.= "var actcode=new Array();\n";
388  $out.= "var actarg=new Array();\n";
389  foreach ($actcode as $k => $v) {
390  $out.= "actcode[$k]='$v';\n";
391  $out.= "actarg[$k]='" . $actarg[$k] . "';\n";
392  }
393  $out.= "sendActionNotification(actcode,actarg);\n";
394  $this->action->clearActionDone();
395  }
396  }
397  return ($out);
398  }
399 
400  function ParseJs(&$out)
401  {
402  $out = preg_replace("/\[JS:REF\]/e", "\$this->GenJsRef()", $out);
403 
404  $out = preg_replace("/\[JS:CODE\]/e", "\$this->GenJsCode(true)", $out);
405 
406  $out = preg_replace("/\[JS:CODENLOG\]/e", "\$this->GenJsCode(false)", $out);
407  }
408 
409  function GenCssRef()
410  {
411  $js = "";
412  $list = $this->action->parent->GetCssRef();
413 
414  foreach ($list as $k => $v) {
415  $js.= "<link rel=\"stylesheet\" type=\"text/css\" href=\"$v\">\n";
416  }
417  return $js;
418  }
419 
420  function GenCssCode()
421  {
422  $list = $this->action->parent->GetCssCode();
423  reset($list);
424  $out = "";
425  while (list($k, $v) = each($list)) {
426  $out.= $v . "\n";
427  }
428  return ($out);
429  }
430  function ParseCss(&$out)
431  {
432  $out = preg_replace("/\[CSS:REF\]/e", "\$this->GenCssRef()", $out);
433 
434  $out = preg_replace("/\[CSS:CODE\]/e", "\$this->GenCssCode()", $out);
435  }
436  function gen()
437  {
438  if ($this->noparse) return $this->template;
439  // if used in an app , set the app params
440  if (is_object($this->action)) {
441  $list = $this->action->parent->GetAllParam();
442  while (list($k, $v) = each($list)) {
443  $this->set($k, $v);
444  }
445  }
446  $out = $this->template;
447 
448  $this->ParseBlock($out);
449  $this->rif = & $this->rkey;
450  $this->ParseIf($out);
451  // Parse IMG: and LAY: tags
452  $this->ParseText($out);
453  $this->ParseKey($out);
454  $this->ParseRef($out);
455  $this->ParseZone($out);
456  $this->ParseJs($out);
457  $this->ParseCss($out);
458 
459  return ($out);
460  }
461  /**
462  * Count number of execute() calls on the stack to detect infinite recursive loops
463  * @param string class name to track
464  * @param string function/method name to track
465  * @return array array('count' => $callCount, 'delta' => $callDelta, 'depth' => $stackDepth)
466  */
467  function getRecursionCount($class, $function)
468  {
469  $count = 0;
470  $curDepth = 0;
471  $prevDepth = 0;
472  $delta = 0;
473 
474  $bt = debug_backtrace(false);
475  $btCount = count($bt);
476  for ($i = $btCount - 2; $i >= 0; $i--) {
477  $curDepth++;
478  if ($class == $bt[$i]['class'] && $function == $bt[$i]['function']) {
479  $delta = $curDepth - $prevDepth;
480  $prevDepth = $curDepth;
481  $count++;
482  }
483  }
484 
485  return array(
486  'count' => $count,
487  'delta' => $delta,
488  'depth' => $curDepth
489  );
490  }
491  /**
492  * Print a recursion count error message and stop execution
493  * @param string class name to display
494  * @param string function/method name to display
495  * @param integer the call count that triggered the error
496  */
497  function printRecursionCountError($class, $function, $count)
498  {
499  include_once ('WHAT/Lib.Prefix.php');
500 
501  $http_code = 500;
502  $http_reason = "Recursion Count Error";
503  header(sprintf("HTTP/1.1 %s %s", $http_code, $http_reason));
504 
505  print "<html><head>\n";
506  print "<title>" . htmlspecialchars($http_reason) . "</title>\n";
507  print "</head></body>\n";
508 
509  print "<h1>" . sprintf("%s %s", htmlspecialchars($http_code) , htmlspecialchars($http_reason)) . "</h1>\n";
510 
511  $message = sprintf("Infinite recursive loop in %s::%s() (call count = '%s')", $class, $function, $count);
512  print "<h2>" . htmlspecialchars($message) . "</h2>\n";
513  error_log(sprintf("%s::%s Error: %s", $class, $function, $message));
514 
515  print "</body></html>\n";
516  exit;
517  }
518 }
519 ?>
← centre documentaire © anakeen - published under CC License - Dynacase