File modules/cms/generator/TemplateGenerator.class.php
Last commit: Fri Feb 17 02:02:18 2023 +0100 Jan Dankert Refactoring: Script-context should be the same in all environments; New: DslPdf for creating PDF with scriptbox ;)
1 <?php 2 3 4 namespace cms\generator; 5 6 7 use cms\base\Configuration; 8 use cms\generator\dsl\CMSDslInterpreter; 9 use cms\generator\dsl\DslPage; 10 use cms\model\File; 11 use cms\model\Project; 12 use cms\model\Template; 13 use cms\model\TemplateModel; 14 use dsl\DslException; 15 use dsl\DslTemplate; 16 use dsl\standard\Data; 17 use http\Exception\InvalidArgumentException; 18 use logger\Logger; 19 use util\exception\GeneratorException; 20 use util\exception\ObjectNotFoundException; 21 use util\Mustache; 22 use util\Text; 23 use util\text\TextMessage; 24 25 26 class TemplateGenerator 27 { 28 29 private $templateId; 30 private $modelId; 31 private $scheme; 32 33 public function __construct($templateId, $modelId, $scheme ) 34 { 35 $this->templateId = $templateId; 36 $this->modelId = $modelId; 37 $this->scheme = $scheme; 38 } 39 40 41 /** 42 * Generates the template content. 43 * 44 * @param $data array values 45 * @return String Inhalt 46 * @throws GeneratorException|ObjectNotFoundException 47 */ 48 public function generateValue( $data ) 49 { 50 $template = new Template( $this->templateId ); 51 $template->load(); 52 53 // Get a List with ElementId->ElementName 54 $elements = array_map(function($element) { 55 return $element->name; 56 },$template->getElements() ); 57 58 $templatemodel = new TemplateModel( $template->templateid, $this->modelId ); 59 if ( $this->scheme == Producer::SCHEME_PREVIEW ) 60 $templatemodel->load(); 61 else 62 $templatemodel->loadForPublic(); 63 64 $src = $templatemodel->src; 65 66 // No we are collecting the data and are fixing some old stuff. 67 if ( DEVELOPMENT ) 68 Logger::trace( 'generating template with data: '.print_r($data,true) ); 69 70 switch( $templatemodel->getFormat() ) { 71 case TemplateModel::FORMAT_MUSTACHE_TEMPLATE: 72 foreach( $elements as $elementId=>$elementName ) 73 { 74 // The following code is for old template values: 75 76 // convert {{<id>}} to {{<name>}} 77 $src = str_replace( '{{'.$elementId.'}}','{{'.$elementName.'}}',$src ); 78 79 $src = str_replace( '{{IFNOTEMPTY:'.$elementId.':BEGIN}}','{{#'.$elementName.'}}',$src ); 80 $src = str_replace( '{{IFNOTEMPTY:'.$elementId.':END}}' ,'{{/'.$elementName.'}}',$src ); 81 $src = str_replace( '{{IFEMPTY:' .$elementId.':BEGIN}}','{{^'.$elementName.'}}',$src ); 82 $src = str_replace( '{{IFEMPTY:' .$elementId.':END}}' ,'{{/'.$elementName.'}}',$src ); 83 84 $src = str_replace( '{{->'.$elementId.'}}','',$src ); 85 } 86 87 // Now we have collected all data, lets call the template engine: 88 89 $mustache = new Mustache(); 90 $mustache->escape = null; // No HTML escaping, this is the job of this CMS ;) 91 $mustache->partialLoader = function( $name ) use ($template) { 92 93 if ( substr($name,0,5) == 'file:') { 94 $fileid = intval( substr($name,5) ); 95 $file = new File( $fileid ); 96 return $file->loadValue(); 97 } 98 99 100 $project = Project::create( $template->projectid ); 101 $templateid = array_search($name,$project->getTemplates() ); 102 103 if ( ! $templateid ) 104 throw new \InvalidArgumentException( TextMessage::create('template ${name} not found',['name'=>$name]) ); 105 106 if ( $templateid == $template->templateid ) 107 throw new \InvalidArgumentException('Template recursion detected on template-id '.$templateid); 108 109 110 $templatemodel = new TemplateModel( $templateid, $this->modelId ); 111 $templatemodel->load(); 112 113 return $templatemodel->src; 114 }; 115 116 try { 117 $mustache->parse($src); 118 } catch (\Exception $e) { 119 120 return new GeneratorException("Mustache template rendering failed:\n".$e->getMessage()); 121 } 122 $src = $mustache->render( $data ); 123 break; 124 125 126 case TemplateModel::FORMAT_RATSCRIPT_TEMPLATE: 127 try { 128 $templateParser = new DslTemplate(); 129 $templateParser->parseTemplate($src); 130 131 $src= $templateParser->script; 132 133 } catch (DslException $e) { 134 throw new GeneratorException('Parsing of Script-Template failed',$e); 135 } 136 137 // here is intentionally no "break" statement! 138 // The generated source will be executed in the next case. 139 140 141 case TemplateModel::FORMAT_RATSCRIPT: 142 try { 143 144 $executor = new CMSDslInterpreter(); 145 $executor->addContext( $data ); 146 $executor->addContext( [ 'data' => new Data($data)] ); 147 148 $executor->runCode($src); 149 150 // Ausgabe ermitteln. 151 $src = $executor->getOutput(); 152 } catch (DslException $e) { 153 Logger::warn($e); 154 throw new GeneratorException("Error in script:\n".Text::makeLineNumbers($src),$e ); 155 } 156 break; 157 158 default: 159 throw new InvalidArgumentException('Format of template source is unknown: '.$templatemodel->getFormat() ); 160 } 161 162 163 164 // should we do a UTF-8-escaping here? 165 // Default should be off, because if you are fully using utf-8 (you should do), this is unnecessary. 166 if ( Configuration::subset('publish' )->is('escape_8bit_characters') ) 167 if ( substr($this->getMimeType(),-4) == 'html' ) 168 $src = Text::translateutf8tohtml($src); 169 170 return $src; 171 } 172 173 174 /** 175 * @return String 176 */ 177 public function getMimeType() 178 { 179 // A MIME type has two parts: a type and a subtype. They are separated by a slash (/) 180 $templateModel = new TemplateModel( $this->templateId,$this->modelId ); 181 $templateModel->load(); 182 183 return $templateModel->mimeType(); 184 } 185 }
Downloadmodules/cms/generator/TemplateGenerator.class.php
History Fri, 17 Feb 2023 02:02:18 +0100 Jan Dankert Refactoring: Script-context should be the same in all environments; New: DslPdf for creating PDF with scriptbox ;) Sat, 28 Jan 2023 19:10:47 +0100 Jan Dankert New: Templates may be rendered as Mustache, Script and Script template. Mon, 27 Jun 2022 01:11:02 +0200 Jan Dankert New: Secure Flag for Script Interpreter which is enabled by default. Mon, 27 Jun 2022 00:40:42 +0200 Jan Dankert New: Marker interface 'Scriptable', Proxy class for MQTT, help() method in Scripts. Sun, 26 Jun 2022 12:51:07 +0200 Jan Dankert New: DSL can be controlled by flags; support for error messages; support for negativ numbers. Tue, 7 Jun 2022 23:29:53 +0200 Jan Dankert New: The DSL may be used as a JSP-like template language. Fri, 18 Mar 2022 22:38:42 +0100 dankert Refactoring: Extracted the TemplateGenerator out of the PageGenerator.