ILIAS  release_8 Revision v8.24
IT.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
5// +----------------------------------------------------------------------+
6// | Copyright (c) 1997-2005 Ulf Wendel, Pierre-Alain Joye |
7// +----------------------------------------------------------------------+
8// | This source file is subject to the New BSD license, That is bundled |
9// | with this package in the file LICENSE, and is available through |
10// | the world-wide-web at |
11// | http://www.opensource.org/licenses/bsd-license.php |
12// | If you did not receive a copy of the new BSD license and are unable |
13// | to obtain it through the world-wide-web, please send a note to |
14// | pajoye@php.net, so we can mail you a copy immediately. |
15// +----------------------------------------------------------------------+
16// | Author: Ulf Wendel <ulf.wendel@phpdoc.de> |
17// | Pierre-Alain Joye <pajoye@php.net> |
18// +----------------------------------------------------------------------+
19
20require_once __DIR__ . '/../../exceptions/class.ilTemplateException.php';
21
98{
99 public const IT_OK = 1;
100 public const IT_ERROR = -1;
101 public const IT_TPL_NOT_FOUND = -2;
102 public const IT_BLOCK_NOT_FOUND = -3;
103 public const IT_BLOCK_DUPLICATE = -4;
104 public const IT_UNKNOWN_OPTION = -6;
105 public const IT_DEFAULT_BLOCK = '__global__';
106
110 public array $err = [];
111
115 public bool $clearCache = false;
116
120 public string $openingDelimiter = '{';
121
125 public string $closingDelimiter = '}';
126
132 public string $blocknameRegExp = '[\.0-9A-Za-z_-]+';
133
139 public string $variablenameRegExp = '[\.0-9A-Za-z_-]+';
140
145 public string $variablesRegExp = '';
146
150 public string $removeVariablesRegExp = '';
151
155 public bool $removeUnknownVariables = true;
156
160 public bool $removeEmptyBlocks = true;
161
165 public string $blockRegExp = '';
166
171
175 public string $template = '';
176
180 public array $blocklist = [];
181
185 public array $blockdata = [];
186
190 public array $blockvariables = [];
191
195 public array $blockparents = [];
196
200 public array $blockinner = [];
201
221 public array $touchedBlocks = [];
222
229 public array $variableCache = [];
230
237 public bool $clearCacheOnParse = false;
238
243 public string $fileRoot = '';
244
248 public bool $flagBlocktrouble = false;
249
253 public bool $flagGlobalParsed = false;
254
264 public bool $flagCacheTemplatefile = true;
265
269 public string $lastTemplatefile = '';
270
279 public array $_options = [
280 'preserve_data' => false,
281 'use_preg' => true
282 ];
283
287 protected string $real_filename = '';
288
298 public function __construct(string $root = '', array $options = null)
299 {
300 if (!is_null($options)) {
301 $this->setOptions($options);
302 }
303 $this->variablesRegExp = '@' . $this->openingDelimiter .
304 '(' . $this->variablenameRegExp . ')' .
305 $this->closingDelimiter . '@sm';
306 $this->removeVariablesRegExp = '@' . $this->openingDelimiter .
307 "\s*(" . $this->variablenameRegExp .
308 ")\s*" . $this->closingDelimiter . '@sm';
309
310 $this->blockRegExp = '@<!--\s+BEGIN\s+(' . $this->blocknameRegExp .
311 ')\s+-->(.*)<!--\s+END\s+\1\s+-->@sm';
312
313 $this->setRoot($root);
314 }
315
321 public function setOption(string $option, $value): int
322 {
323 if (array_key_exists($option, $this->_options)) {
324 $this->_options[$option] = $value;
325 return self::IT_OK;
326 }
327
328 throw new ilTemplateException($this->errorMessage(self::IT_UNKNOWN_OPTION) . ": '$option'");
329 }
330
336 public function setOptions(array $options): int
337 {
338 foreach ($options as $option => $value) {
339 $this->setOption($option, $value);
340 }
341
342 return self::IT_OK;
343 }
344
349 public function show(string $block = self::IT_DEFAULT_BLOCK): void
350 {
351 print $this->get($block);
352 }
353
358 public function get(string $block = self::IT_DEFAULT_BLOCK): string
359 {
360 if ($block === self::IT_DEFAULT_BLOCK && !$this->flagGlobalParsed) {
361 $this->parse();
362 }
363
364 if (!isset($this->blocklist[$block])) {
365 throw new ilTemplateException($this->errorMessage(self::IT_BLOCK_NOT_FOUND) . '"' . $block . "'");
366 }
367
368 if (isset($this->blockdata[$block])) {
369 $ret = $this->blockdata[$block];
370 if ($this->clearCache) {
371 unset($this->blockdata[$block]);
372 }
373 if ($this->_options['preserve_data']) {
374 $ret = str_replace(
375 $this->openingDelimiter .
376 '%preserved%' . $this->closingDelimiter,
377 $this->openingDelimiter,
378 $ret
379 );
380 }
381 return $ret;
382 }
383
384 return '';
385 }
386
394 public function parse(string $block = self::IT_DEFAULT_BLOCK, bool $flag_recursion = false): bool
395 {
396 static $regs, $values;
397
398 if (!isset($this->blocklist[$block])) {
399 throw new ilTemplateException($this->errorMessage(self::IT_BLOCK_NOT_FOUND) . '"' . $block . "'");
400 }
401
402 if (self::IT_DEFAULT_BLOCK === $block) {
403 $this->flagGlobalParsed = true;
404 }
405
406 if (!$flag_recursion) {
407 $regs = [];
408 $values = [];
409 }
410 $outer = $this->blocklist[$block];
411 $empty = true;
412
413 if ($this->clearCacheOnParse) {
414 foreach ($this->variableCache as $name => $value) {
415 $regs[] = $this->openingDelimiter .
417 $values[] = $value;
418 $empty = false;
419 }
420 $this->variableCache = [];
421 } else {
422 foreach ($this->blockvariables[$block] as $allowedvar => $v) {
423 if (isset($this->variableCache[$allowedvar])) {
424 $regs[] = $this->openingDelimiter .
425 $allowedvar . $this->closingDelimiter;
426 $values[] = $this->variableCache[$allowedvar];
427 unset($this->variableCache[$allowedvar]);
428 $empty = false;
429 }
430 }
431 }
432
433 if (isset($this->blockinner[$block])) {
434 foreach ($this->blockinner[$block] as $k => $innerblock) {
435 $this->parse($innerblock, true);
436 if ($this->blockdata[$innerblock] !== '') {
437 $empty = false;
438 }
439
440 $placeholder = $this->openingDelimiter . "__" .
441 $innerblock . "__" . $this->closingDelimiter;
442 $outer = str_replace(
443 $placeholder,
444 $this->blockdata[$innerblock],
445 $outer
446 );
447 $this->blockdata[$innerblock] = "";
448 }
449 }
450
451 if (!$flag_recursion && 0 !== count($values)) {
452 if ($this->_options['use_preg']) {
453 $regs = array_map(
454 [
455 &$this,
456 '_addPregDelimiters'
457 ],
458 $regs
459 );
460 $funcReplace = 'preg_replace';
461 } else {
462 $funcReplace = 'str_replace';
463 }
464
465 if ($this->_options['preserve_data']) {
466 $values = array_map(
467 [&$this, '_preserveOpeningDelimiter'],
468 $values
469 );
470 }
471
472 $outer = $funcReplace($regs, $values, $outer);
473
474 if ($this->removeUnknownVariables) {
475 $outer = preg_replace($this->removeVariablesRegExp, "", $outer);
476 }
477 }
478
479 if ($empty) {
480 if (!$this->removeEmptyBlocks) {
481 $this->blockdata[$block] .= $outer;
482 } elseif (isset($this->touchedBlocks[$block])) {
483 $this->blockdata[$block] .= $outer;
484 unset($this->touchedBlocks[$block]);
485 }
486 } elseif (empty($this->blockdata[$block])) {
487 $this->blockdata[$block] = $outer;
488 } else {
489 $this->blockdata[$block] .= $outer;
490 }
491
492 return $empty;
493 }
494
499 public function parseCurrentBlock(): bool
500 {
501 return $this->parse($this->currentBlock);
502 }
503
514 public function setVariable($variable, $value = ''): void
515 {
516 if (is_array($variable)) {
517 $this->variableCache = array_merge(
518 $this->variableCache,
519 $variable
520 );
521 } else {
522 $this->variableCache[$variable] = $value;
523 }
524 }
525
531 public function setCurrentBlock(string $block = self::IT_DEFAULT_BLOCK): bool
532 {
533 if (!isset($this->blocklist[$block])) {
534 throw new ilTemplateException($this->errorMessage(self::IT_BLOCK_NOT_FOUND) . '"' . $block . "'");
535 }
536
537 $this->currentBlock = $block;
538
539 return true;
540 }
541
546 public function touchBlock(string $block): bool
547 {
548 if (!isset($this->blocklist[$block])) {
549 throw new ilTemplateException($this->errorMessage(self::IT_BLOCK_NOT_FOUND) . '"' . $block . "'");
550 }
551
552 $this->touchedBlocks[$block] = true;
553
554 return true;
555 }
556
564 protected function init(): void
565 {
566 $this->free();
568
569 if ($blockdata = $blocks->get($this->real_filename)) {
570 $this->blockdata = $blockdata['blockdata'];
571 $this->blocklist = $blockdata['blocklist'];
572 } else {
574 $this->findBlocks($this->template);
575 $blockdata['blockdata'] = $this->blockdata;
576 $blockdata['blocklist'] = $this->blocklist;
577 $blocks->set($this->real_filename, $blockdata, 60);
578 }
579
580 // we don't need it any more
581 $this->template = '';
582
584 if ($blockvariables = $variables->get($this->real_filename)) {
585 $this->blockvariables = $blockvariables;
586 } else {
587 $this->buildBlockvariablelist();
588 $variables->set($this->real_filename, $this->blockvariables, 60);
589 }
590 }
591
596 public function free(): void
597 {
598 $this->err = [];
599
600 $this->currentBlock = self::IT_DEFAULT_BLOCK;
601
602 $this->variableCache = [];
603 $this->blocklist = [];
604 $this->touchedBlocks = [];
605
606 $this->flagBlocktrouble = false;
607 $this->flagGlobalParsed = false;
608 }
609
616 public function setTemplate(
617 string $template,
618 bool $removeUnknownVariables = true,
619 bool $removeEmptyBlocks = true
620 ): bool {
621 $this->removeUnknownVariables = $removeUnknownVariables;
622 $this->removeEmptyBlocks = $removeEmptyBlocks;
623
624 if ($template === '' && $this->flagCacheTemplatefile) {
625 $this->variableCache = [];
626 $this->blockdata = [];
627 $this->touchedBlocks = [];
628 $this->currentBlock = self::IT_DEFAULT_BLOCK;
629 } else {
630 $this->template =
631 '<!-- BEGIN ' . self::IT_DEFAULT_BLOCK . ' -->' .
632 $template .
633 '<!-- END ' . self::IT_DEFAULT_BLOCK . ' -->';
634 $this->init();
635 }
636
637 if ($this->flagBlocktrouble) {
638 return false;
639 }
640
641 return true;
642 }
643
648 public function loadTemplatefile(
649 string $filename,
650 bool $removeUnknownVariables = true,
651 bool $removeEmptyBlocks = true
652 ): bool {
653 $template = '';
654 if (!$this->flagCacheTemplatefile ||
655 $this->lastTemplatefile !== $filename
656 ) {
657 $template = $this->getFile($filename);
658 }
659 $this->lastTemplatefile = $filename;
660
661 return $template !== '' && $this->setTemplate(
662 $template,
663 $removeUnknownVariables,
664 $removeEmptyBlocks
665 );
666 }
667
674 public function setRoot(string $root): void
675 {
676 if ($root !== '' && substr($root, -1) !== '/') {
677 $root .= '/';
678 }
679
680 $this->fileRoot = $root;
681 }
682
686 public function buildBlockvariablelist(): void
687 {
688 foreach ($this->blocklist as $name => $content) {
689 preg_match_all($this->variablesRegExp, $content, $regs);
690
691 if (count($regs[1]) !== 0) {
692 foreach ($regs[1] as $var) {
693 $this->blockvariables[$name][$var] = true;
694 }
695 } else {
696 $this->blockvariables[$name] = [];
697 }
698 }
699 }
700
705 public function findBlocks(string $string): array
706 {
707 $blocklist = [];
708 if (preg_match_all($this->blockRegExp, $string, $regs, PREG_SET_ORDER)) {
709 foreach ($regs as $match) {
710 $blockname = $match[1];
711 $blockcontent = $match[2];
712
713 if (isset($this->blocklist[$blockname])) {
714 throw new ilTemplateException($this->errorMessage(self::IT_BLOCK_DUPLICATE, $blockname));
715 }
716
717 $this->blocklist[$blockname] = $blockcontent;
718 $this->blockdata[$blockname] = "";
719
720 $blocklist[] = $blockname;
721
722 $inner = $this->findBlocks($blockcontent);
723 foreach ($inner as $name) {
724 $pattern = sprintf(
725 '@<!--\s+BEGIN\s+%s\s+-->(.*)<!--\s+END\s+%s\s+-->@sm',
726 $name,
727 $name
728 );
729
730 $this->blocklist[$blockname] = preg_replace(
731 $pattern,
732 $this->openingDelimiter .
733 '__' . $name . '__' .
734 $this->closingDelimiter,
735 $this->blocklist[$blockname]
736 );
737 $this->blockinner[$blockname][] = $name;
738 $this->blockparents[$name] = $blockname;
739 }
740 }
741 }
742
743 return $blocklist;
744 }
745
750 public function getFile(string $filename): string
751 {
752 if ($filename[0] === '/' && substr($this->fileRoot, -1) === '/') {
753 $filename = substr($filename, 1);
754 }
755
756 $filename = $this->fileRoot . $filename;
757
758 $this->real_filename = $filename;
760 if (!$content = $ilGlobalCache->get($filename)) {
761 if (!($fh = @fopen($filename, 'rb'))) {
762 throw new ilTemplateException($this->errorMessage(self::IT_TPL_NOT_FOUND) . ': "' . $filename . '"');
763 }
764
765 $fsize = filesize($filename);
766 if ($fsize < 1) {
767 fclose($fh);
768 return '';
769 }
770
771 $content = fread($fh, $fsize);
772 $ilGlobalCache->set($filename, $content, 60);
773 fclose($fh);
774 }
775
776 return $content;
777 }
778
783 public function _addPregDelimiters(string $str): string
784 {
785 return '@' . $str . '@';
786 }
787
791 public function _preserveOpeningDelimiter(string $str): string
792 {
793 return (false === strpos($str, $this->openingDelimiter)) ?
794 $str :
795 str_replace(
796 $this->openingDelimiter,
797 $this->openingDelimiter .
798 '%preserved%' . $this->closingDelimiter,
799 $str
800 );
801 }
802
806 public function errorMessage(int $value, string $blockname = ''): string
807 {
808 static $errorMessages;
809 if (!isset($errorMessages)) {
810 $errorMessages = [
811 self::IT_OK => '',
812 self::IT_ERROR => 'unknown error',
813 self::IT_TPL_NOT_FOUND => 'Cannot read the template file',
814 self::IT_BLOCK_NOT_FOUND => 'Cannot find this block',
815 self::IT_BLOCK_DUPLICATE => 'The name of a block must be' .
816 ' uniquewithin a template.' .
817 ' Found "' . $blockname . '" twice.' .
818 'Unpredictable results ' .
819 'may appear.',
820 self::IT_UNKNOWN_OPTION => 'Unknown option'
821 ];
822 }
823
824 return $errorMessages[$value] ?? $errorMessages[self::IT_ERROR];
825 }
826}
$filename
Definition: buildRTE.php:78
Integrated Template - IT Well there's not much to say about it.
Definition: IT.php:98
string $closingDelimiter
Last character of a variable placeholder ( {VARIABLE_}_ ).
Definition: IT.php:125
string $variablenameRegExp
RegExp matching a variable placeholder in the template.
Definition: IT.php:139
string $blockRegExp
RegExp used to find blocks an their content, filled by the constructor.
Definition: IT.php:165
const IT_BLOCK_DUPLICATE
Definition: IT.php:103
bool $flagCacheTemplatefile
EXPERIMENTAL! FIXME! Flag indication that a template gets cached.
Definition: IT.php:264
const IT_ERROR
Definition: IT.php:100
free()
Clears all datafields of the object.
Definition: IT.php:596
array $variableCache
Variable cache.
Definition: IT.php:229
buildBlockvariablelist()
Build a list of all variables within of a block.
Definition: IT.php:686
init()
Clears all datafields of the object and rebuild the internal blocklist LoadTemplatefile() and setTemp...
Definition: IT.php:564
array $blockparents
Array of block parents.
Definition: IT.php:195
bool $removeEmptyBlocks
Controls the handling of empty blocks, default is remove.
Definition: IT.php:160
touchBlock(string $block)
Preserves an empty block even if removeEmptyBlocks is true.
Definition: IT.php:546
const IT_DEFAULT_BLOCK
Definition: IT.php:105
setOption(string $option, $value)
Sets the option for the template class.
Definition: IT.php:321
array $blockinner
Array of inner blocks of a block.
Definition: IT.php:200
setCurrentBlock(string $block=self::IT_DEFAULT_BLOCK)
Sets the name of the current block that is the block where variables are added.
Definition: IT.php:531
_addPregDelimiters(string $str)
Adds delimiters to a string, so it can be used as a pattern in preg_* functions.
Definition: IT.php:783
string $template
Content of the template.
Definition: IT.php:175
parse(string $block=self::IT_DEFAULT_BLOCK, bool $flag_recursion=false)
Parses the given block.
Definition: IT.php:394
_preserveOpeningDelimiter(string $str)
Replaces an opening delimiter by a special string.
Definition: IT.php:791
const IT_TPL_NOT_FOUND
Definition: IT.php:101
findBlocks(string $string)
Recusively builds a list of all blocks within the template.
Definition: IT.php:705
string $fileRoot
Root directory for all file operations.
Definition: IT.php:243
loadTemplatefile(string $filename, bool $removeUnknownVariables=true, bool $removeEmptyBlocks=true)
Reads a template file from the disk.
Definition: IT.php:648
const IT_UNKNOWN_OPTION
Definition: IT.php:104
array $blockdata
Array with the parsed content of a block.
Definition: IT.php:185
string $openingDelimiter
First character of a variable placeholder ( _{_VARIABLE} ).
Definition: IT.php:120
getFile(string $filename)
Reads a file from disk and returns its content.
Definition: IT.php:750
parseCurrentBlock()
Parses the current block.
Definition: IT.php:499
string $removeVariablesRegExp
RegExp used to strip unused variable placeholder.
Definition: IT.php:150
setTemplate(string $template, bool $removeUnknownVariables=true, bool $removeEmptyBlocks=true)
Sets the template.
Definition: IT.php:616
array $blocklist
Array of all blocks and their content.
Definition: IT.php:180
array $err
Contains the error objects.
Definition: IT.php:110
setRoot(string $root)
Sets the file root.
Definition: IT.php:674
const IT_OK
Definition: IT.php:99
array $blockvariables
Array of variables in a block.
Definition: IT.php:190
show(string $block=self::IT_DEFAULT_BLOCK)
Print a certain block with all replacements done.
Definition: IT.php:349
const IT_BLOCK_NOT_FOUND
Definition: IT.php:102
setVariable($variable, $value='')
Sets a variable value.
Definition: IT.php:514
bool $flagBlocktrouble
Internal flag indicating that a blockname was used multiple times.
Definition: IT.php:248
bool $flagGlobalParsed
Flag indicating that the global block was parsed.
Definition: IT.php:253
bool $clearCacheOnParse
Clear the variable cache on parse? If you're not an expert just leave the default false.
Definition: IT.php:237
bool $clearCache
Clear cache on get()?
Definition: IT.php:115
__construct(string $root='', array $options=null)
Builds some complex regular expressions and optinally sets the file root directory.
Definition: IT.php:298
string $currentBlock
Name of the current block.
Definition: IT.php:170
array $_options
$_options['preserve_data'] Whether to substitute variables and remove empty placeholders in data pass...
Definition: IT.php:279
string $variablesRegExp
RegExp used to find variable placeholder, filled by the constructor.
Definition: IT.php:145
string $blocknameRegExp
RegExp matching a block in the template.
Definition: IT.php:132
string $lastTemplatefile
EXPERIMENTAL! FIXME!
Definition: IT.php:269
setOptions(array $options)
Sets the options for the template class.
Definition: IT.php:336
string $real_filename
Holds the real template file name.
Definition: IT.php:287
array $touchedBlocks
List of blocks to preverse even if they are "empty".
Definition: IT.php:221
bool $removeUnknownVariables
Controls the handling of unknown variables, default is remove.
Definition: IT.php:155
errorMessage(int $value, string $blockname='')
Return a textual error message for a IT error code.
Definition: IT.php:806
return true
static getInstance(?string $component)
static log(string $message, int $log_level)
if($format !==null) $name
Definition: metadata.php:247