File modules/cms/model/Element.class.php

Last commit: Wed Apr 17 00:34:07 2024 +0200	Jan Dankert	New: Inputfields for coordinates; coordinates are stored in the now 64bit-number-field of the value.
1 <?php 2 namespace cms\model; 3 4 5 use cms\base\DB as Db; 6 use cms\generator\FileContext; 7 use cms\generator\link\PreviewLink; 8 use cms\generator\Producer; 9 use util\ArrayUtils; 10 use logger\Logger; 11 12 /** 13 * Element. 14 * 15 * An element is a placeholder in a template. 16 * It is of a specific type, e.g. text, image, ... 17 * 18 * @author Jan Dankert 19 */ 20 class Element extends ModelBase 21 { 22 // the list of all available element types: 23 const ELEMENT_TYPE_DATE = 1; 24 const ELEMENT_TYPE_NUMBER = 2; 25 const ELEMENT_TYPE_TEXT = 3; 26 const ELEMENT_TYPE_INFO = 4; 27 const ELEMENT_TYPE_INFODATE = 5; 28 const ELEMENT_TYPE_LINK = 6; 29 const ELEMENT_TYPE_LONGTEXT = 7; 30 const ELEMENT_TYPE_CODE = 8; 31 const ELEMENT_TYPE_DYNAMIC = 9; 32 const ELEMENT_TYPE_SELECT = 10; 33 const ELEMENT_TYPE_COPY = 11; 34 const ELEMENT_TYPE_LINKINFO = 12; 35 const ELEMENT_TYPE_LINKDATE = 13; 36 const ELEMENT_TYPE_INSERT = 14; 37 38 /** 39 * Data. 40 */ 41 const ELEMENT_TYPE_DATA = 15; 42 43 /** 44 * Coordinates. 45 */ 46 const ELEMENT_TYPE_COORD = 16; 47 const ELEMENT_TYPE_CHECKBOX = 17; 48 49 const ELEMENT_FORMAT_TEXT = 0; 50 const ELEMENT_FORMAT_HTML = 1; 51 const ELEMENT_FORMAT_WIKI = 2; 52 const ELEMENT_FORMAT_MARKDOWN = 3; 53 const ELEMENT_FORMAT_HTML_SOURCE = 4; 54 55 const ELEMENT_FLAG_HTML_ALLOWED = 1; 56 const ELEMENT_FLAG_ALL_LANGUAGES = 2; 57 const ELEMENT_FLAG_WRITABLE = 4; 58 const ELEMENT_FLAG_WITH_ICON = 8; 59 const ELEMENT_FLAG_INHERIT = 16; 60 61 /** 62 * Eindeutige ID dieses Elementes 63 * @type Integer 64 */ 65 var $elementid; 66 67 /** 68 * Template-ID zu der dieses Elementes geh?rt 69 * @type Integer 70 */ 71 var $templateid; 72 73 /** 74 * Typ des Elementes 75 * Folgende Typen sind moeglich: 76 * <ul> 77 * <li>text</li> 78 * <li>longtext</li> 79 * <li>select</li> 80 * <li>number</li> 81 * <li>link</li> 82 * <li>date</li> 83 * <li>insert</li> 84 * <li>linkinfo</li> 85 * <li>linkdate</li> 86 * <li>code</li> 87 * <li>info</li> 88 * <li>infodate</li> 89 * </ul> 90 * 91 * @type String 92 * @deprecated use #typeid 93 */ 94 var $type; 95 96 /** 97 * 98 * Type of the element. Must be a constant value of ELEMENT_TYPE_*. 99 * @var integer Type of element 100 */ 101 public $typeid; 102 103 /** 104 * Logischer Name dieses Elementes 105 * @type String 106 */ 107 var $name; 108 109 /** 110 * Eingabefeld-Bezeichnung für dieses Element. 111 * @type String 112 */ 113 var $label; 114 115 /** 116 * Beschreibung zu diesem Element 117 * Zu jedem Element kann eine Beschreibung hinterlegt werden, die dem Redakteur bei der Bearbeitung 118 * der Inhalte als Bearbeitungshilfe dienen kann. 119 * @type String 120 */ 121 var $desc; 122 123 /** 124 * Objekt-ID eines Ordners, aus diesem Ordner (samt Unterordner) 125 * k?nnen zu verlinkende Objekte ausgew?hlt werden 126 * @type Integer 127 */ 128 var $folderObjectId = 0; 129 130 /** 131 * Vorausgew�hltes Objekt. 132 * @type Integer 133 */ 134 var $defaultObjectId = 0; 135 136 /** 137 * Schalter ob dieses Element von Redakteuren bearbeiten werden kann 138 * @type bool 139 */ 140 public $writable; 141 142 /** 143 * values are inherited from parent nodes. 144 * @var bool 145 */ 146 public $inherit; 147 148 /** 149 * Schalter, ob dieses Element in allen Sprachen den gleichen Inhalt haben soll 150 * @type bool 151 */ 152 public $allLanguages; 153 154 public static $readonlyElementTypeIds = array( 155 self::ELEMENT_TYPE_COPY,self::ELEMENT_TYPE_LINKINFO,self::ELEMENT_TYPE_LINKDATE,self::ELEMENT_TYPE_INFO,self::ELEMENT_TYPE_INFODATE,self::ELEMENT_TYPE_CODE,self::ELEMENT_TYPE_DYNAMIC 156 ); 157 158 159 /** 160 * Untertyp. 161 * 162 * @var String 163 */ 164 var $subtype = ''; 165 166 /** 167 * @var bool 168 */ 169 var $withIcon = false; 170 var $dateformat = 'r'; 171 172 /* 173 * @deprecated use format. 174 */ 175 public $wiki = false; 176 177 public $format = self::ELEMENT_FORMAT_TEXT; 178 179 /** 180 * @var bool 181 */ 182 public $html = false; 183 184 var $decimals = 0; 185 var $decPoint = '.'; 186 var $thousandSep = ''; 187 var $code = ''; 188 var $defaultText = ''; 189 190 191 /** 192 * Im Konstruktor wird die Element-Id gesetzt 193 * @param Integer Element-Id 194 */ 195 function __construct( $elementid=0 ) 196 { 197 if ( intval($elementid)!=0 ) 198 $this->elementid = $elementid; 199 } 200 201 202 /** 203 * Hinzuf?gen eines Elementes 204 * Das aktuelle Element wird in die Datenbank geschrieben. 205 */ 206 function add() 207 { 208 $sql = Db::sql('SELECT MAX(id) FROM {{element}}'); 209 $this->elementid = intval($sql->getOne())+1; 210 211 $sql = Db::sql( 'INSERT INTO {{element}}'. 212 ' (id,templateid,name,label,descr,typeid,flags) '. 213 " VALUES ( {elementid},{templateid},{name},{label},{description},{typeid},{flags} ) " ); 214 215 $flags = 0; 216 $flags += self::ELEMENT_FLAG_WRITABLE * intval($this->writable); 217 218 $sql->setInt ( 'elementid' ,$this->elementid ); 219 $sql->setString ( 'name' ,$this->name ); 220 $sql->setString ( 'label' ,$this->label ); 221 $sql->setInt ( 'typeid' ,$this->typeid ); 222 $sql->setInt ( 'templateid' ,$this->templateid ); 223 $sql->setInt ( 'flags' ,$flags ); 224 $sql->setString ( 'description',$this->desc ); 225 226 $sql->execute(); 227 } 228 229 230 /** 231 * Lesen des Elementes aus der Datenbank 232 * Alle Eigenschaften des Elementes werden aus der Datenbank gelesen 233 * @throws \util\exception\ObjectNotFoundException 234 */ 235 function load() 236 { 237 if ( intval($this->elementid) != 0 ) 238 { 239 $db = Db::get(); 240 $sql = $db->sql( <<<SQL 241 SELECT * FROM {{element}} 242 WHERE id={elementid} 243 SQL 244 ); 245 $sql->setInt( 'elementid',$this->elementid ); 246 $this->setDatabaseRow( $sql->getRow() ); 247 } 248 } 249 250 251 /** 252 * @param $prop 253 * @throws \util\exception\ObjectNotFoundException 254 */ 255 function setDatabaseRow($prop ) 256 { 257 if ( count($prop) <= 0 ) 258 throw new \util\exception\ObjectNotFoundException("Element not found"); 259 260 $this->elementid = $prop['id' ]; 261 $this->templateid = $prop['templateid']; 262 $this->name = $prop['name' ]; 263 $this->label = $prop['label' ]; 264 $this->desc = $prop['descr' ]; 265 $this->typeid = $prop['typeid' ]; 266 $this->type = Element::getAvailableTypes()[ $this->typeid ]; // name of type 267 $this->subtype = $prop['subtype' ]; 268 269 $this->dateformat = $prop['dateformat']; 270 $this->wiki = $prop['format'] == self::ELEMENT_FORMAT_WIKI; 271 $this->format = $prop['format']; 272 $this->withIcon = (boolean) ($prop['flags'] & self::ELEMENT_FLAG_WITH_ICON ); 273 $this->html = (boolean) ($prop['flags'] & self::ELEMENT_FLAG_HTML_ALLOWED ); 274 $this->allLanguages = (boolean) ($prop['flags'] & self::ELEMENT_FLAG_ALL_LANGUAGES); 275 $this->writable = (boolean) ($prop['flags'] & self::ELEMENT_FLAG_WRITABLE ); 276 $this->inherit = (boolean) ($prop['flags'] & self::ELEMENT_FLAG_INHERIT ); 277 278 if ( !$this->writable) 279 $this->withIcon = false; 280 281 $this->decimals = intval( $prop['decimals' ] ); 282 $this->decPoint = strval( $prop['dec_point' ] ); 283 $this->thousandSep = strval( $prop['thousand_sep' ] ); 284 $this->code = strval( $prop['code' ] ); 285 $this->defaultText = strval( $prop['default_text' ] ); 286 $this->folderObjectId = intval( $prop['folderobjectid' ] ); 287 $this->defaultObjectId = intval( $prop['default_objectid'] ); 288 } 289 290 291 /** 292 * Abspeichern des Elementes 293 * Das aktuelle Element wird in der Datenbank gespeichert 294 */ 295 function save() 296 { 297 $sql = Db::sql( 'UPDATE {{element}}'. 298 ' SET templateid = {templateid},'. 299 ' name = {name},'. 300 ' label = {label},'. 301 ' descr = {desc},'. 302 ' typeid = {typeid},'. 303 ' subtype = {subtype},'. 304 ' dateformat = {dateformat},'. 305 ' flags = {flags},'. 306 ' format = {format},'. 307 ' decimals = {decimals},'. 308 ' dec_point = {decPoint},'. 309 ' thousand_sep = {thousandSep},'. 310 ' code = {code},'. 311 ' default_text = {defaultText},'. 312 ' folderobjectid = {folderObjectId},'. 313 ' default_objectid= {defaultObjectId}'. 314 ' WHERE id={elementid}' ); 315 316 $flags = 0; 317 $flags += self::ELEMENT_FLAG_WITH_ICON * intval($this->withIcon ); 318 $flags += self::ELEMENT_FLAG_HTML_ALLOWED * intval($this->html ); 319 $flags += self::ELEMENT_FLAG_ALL_LANGUAGES * intval($this->allLanguages); 320 $flags += self::ELEMENT_FLAG_WRITABLE * intval($this->writable ); 321 $flags += self::ELEMENT_FLAG_INHERIT * intval($this->inherit ); 322 323 $sql->setInt ( 'elementid' ,$this->elementid ); 324 $sql->setInt ( 'templateid' ,$this->templateid ); 325 $sql->setString ( 'name' ,$this->name ); 326 $sql->setString ( 'label' ,$this->label ); 327 $sql->setString ( 'desc' ,$this->desc ); 328 $sql->setInt ( 'typeid' ,$this->typeid ); 329 $sql->setString ( 'subtype' ,$this->subtype ); 330 $sql->setString ( 'dateformat' ,$this->dateformat ); 331 $sql->setInt ( 'flags' ,$flags ); 332 $sql->setInt ( 'format' ,$this->format ); 333 $sql->setInt ( 'decimals' ,$this->decimals ); 334 $sql->setString ( 'decPoint' ,$this->decPoint ); 335 $sql->setString ( 'thousandSep' ,$this->thousandSep ); 336 $sql->setString ( 'code' ,$this->code ); 337 $sql->setString ( 'defaultText' ,$this->defaultText ); 338 339 if ( intval($this->folderObjectId)==0 ) 340 $sql->setNull( 'folderObjectId' ); 341 else $sql->setInt ( 'folderObjectId' ,$this->folderObjectId ); 342 343 if ( intval($this->defaultObjectId)==0 ) 344 $sql->setNull( 'defaultObjectId' ); 345 else $sql->setInt ( 'defaultObjectId' ,$this->defaultObjectId ); 346 347 $sql->execute(); 348 } 349 350 351 352 /** 353 * Setzt ein Prefix vor den Elementnamen. 354 * @param String Prefix 355 */ 356 function setPrefix( $prefix ) 357 { 358 if ( strrpos($this->name,'%') === FALSE ) 359 $name = $this->name; 360 else 361 list( $oldprefix,$name ) = explode('%',$this->name.'%'); 362 363 $this->name = $prefix.'%'.$name; 364 } 365 366 367 /** 368 * Loeschen des Elementes und aller Inhalte 369 */ 370 public function delete() 371 { 372 $db = Db::get(); 373 374 // Inhalte loeschen. 375 // notwendig, damit die Fremdschlüsselbeziehungen auf diesen Element aufgehoben werden. 376 $this->deleteValues(); 377 378 // Element loeschen 379 $sql = $db->sql('DELETE FROM {{element}} '. 380 ' WHERE id={elementid}' ); 381 $sql->setInt( 'elementid',$this->elementid ); 382 383 $sql->execute(); 384 } 385 386 387 /** 388 * Deletes all values for this element. 389 */ 390 public function deleteValues() 391 { 392 $sql = DB::sql( <<<SQL 393 SELECT id as pagecontentid,contentid 394 FROM {{pagecontent}} 395 WHERE elementid = {elementid} 396 SQL 397 ); 398 $sql->setInt( 'elementid',$this->elementid ); 399 400 foreach( $sql->getAll() as $pagecontentRow ) { 401 $sql = DB::sql( <<<SQL 402 DELETE 403 FROM {{value}} 404 WHERE contentid = {contentid} 405 SQL 406 ); 407 $sql->setInt( 'contentid',$pagecontentRow['contentid'] ); 408 $sql->execute(); 409 410 411 $sql = DB::sql( <<<SQL 412 DELETE 413 FROM {{pagecontent}} 414 WHERE id = {pagecontentid} 415 SQL 416 ); 417 $sql->setInt( 'pagecontentid',$pagecontentRow['pagecontentid'] ); 418 $sql->execute(); 419 420 421 $sql = DB::sql( <<<SQL 422 DELETE 423 FROM {{content}} 424 WHERE id = {contentid} 425 SQL 426 ); 427 $sql->setInt( 'contentid',$pagecontentRow['contentid'] ); 428 $sql->execute(); 429 } 430 } 431 432 433 434 435 /** 436 * Default value 437 * @return string default value 438 */ 439 public function getDefaultValue() 440 { 441 switch( $this->typeid ) 442 { 443 case self::ELEMENT_TYPE_TEXT: 444 case self::ELEMENT_TYPE_LONGTEXT: 445 return $this->defaultText; 446 case self::ELEMENT_TYPE_INFO: 447 return '(i)'; 448 case self::ELEMENT_TYPE_LINKDATE: 449 case self::ELEMENT_TYPE_INFODATE: 450 case self::ELEMENT_TYPE_DATE: 451 return date($this->dateformat); 452 case self::ELEMENT_TYPE_LINK: 453 if ( $this->defaultObjectId ) { 454 $o = new BaseObject($this->defaultObjectId); 455 $o->load(); 456 switch( $o->typeid ) { 457 case BaseObject::TYPEID_FILE: 458 case BaseObject::TYPEID_IMAGE: 459 case BaseObject::TYPEID_TEXT: 460 $linkFormat = new PreviewLink( new FileContext($o->objectid,Producer::SCHEME_PREVIEW)); 461 return $linkFormat->linkToObject($o,$o); 462 case BaseObject::TYPEID_LINK: 463 return ""; 464 case BaseObject::TYPEID_URL: 465 $url = new Url( $o->objectid ); 466 $url->load(); 467 return $url->url; 468 } 469 } 470 return $this->getName(); 471 case 'number'; 472 return '0'; 473 default: 474 return $this->getName(); 475 } 476 } 477 478 /** 479 * a textual representation for all element types. 480 * 481 * @return array id->name 482 */ 483 public static function getAvailableTypes() 484 { 485 return [ 486 self::ELEMENT_TYPE_TEXT => 'text', 487 self::ELEMENT_TYPE_LONGTEXT => 'longtext', 488 self::ELEMENT_TYPE_SELECT => 'select', 489 self::ELEMENT_TYPE_NUMBER => 'number', 490 self::ELEMENT_TYPE_CHECKBOX => 'checkbox', 491 self::ELEMENT_TYPE_LINK => 'link', 492 self::ELEMENT_TYPE_DATE => 'date', 493 self::ELEMENT_TYPE_INSERT => 'insert', 494 self::ELEMENT_TYPE_COPY => 'copy', 495 self::ELEMENT_TYPE_LINKINFO => 'linkinfo', 496 self::ELEMENT_TYPE_LINKDATE => 'linkdate', 497 self::ELEMENT_TYPE_CODE => 'code', 498 self::ELEMENT_TYPE_DYNAMIC => 'dynamic', 499 self::ELEMENT_TYPE_INFO => 'info', 500 self::ELEMENT_TYPE_INFODATE => 'infodate', 501 self::ELEMENT_TYPE_DATA => 'data', 502 self::ELEMENT_TYPE_COORD => 'coord' 503 ]; 504 } 505 506 507 /** 508 * all available formats for text elements. 509 * 510 * @return array id->name 511 */ 512 public static function getAvailableFormats() 513 { 514 return [ 515 self::ELEMENT_FORMAT_TEXT => 'text', 516 self::ELEMENT_FORMAT_WIKI => 'wiki', 517 self::ELEMENT_FORMAT_HTML => 'html', 518 self::ELEMENT_FORMAT_MARKDOWN => 'markdown', 519 self::ELEMENT_FORMAT_HTML_SOURCE => 'htmlsource', 520 ]; 521 } 522 523 524 /** 525 * Ermittelt die Klasse des Element-Typs.<br> 526 * Entweder "info", "text" oder "dynamic". 527 * 528 * @return String 529 */ 530 function getTypeClass() 531 { 532 switch( $this->type ) 533 { 534 case 'text': 535 case 'longtext': 536 case 'select': 537 case 'number': 538 case 'link': 539 case 'date': 540 case 'list': 541 case 'insert': 542 return 'text'; 543 544 case 'code': 545 case 'dynamic': 546 return 'dynamic'; 547 548 case 'copy': 549 case 'info': 550 case 'infodate': 551 case 'linkinfo': 552 case 'linkdate': 553 default: 554 return 'info'; 555 } 556 } 557 558 559 function getSelectItems() 560 { 561 $parameters = explode( "\n",$this->code ); 562 $items = array(); 563 564 foreach( $parameters as $it ) 565 { 566 $paar = explode( ":",$it,2 ); 567 $param_name = trim($paar[0]); 568 569 if ( count($paar) > 1 ) 570 $param_value = trim($paar[1]); 571 else 572 $param_value = trim($paar[0]); 573 574 // Wenn Inhalt mit "'" beginnt und mit "'" aufhoert, dann diese Zeichen abschneiden 575 if ( substr($param_value,0,1) == "'" && substr($param_value,strlen($param_value)-1,1) == "'" ) 576 $param_value = substr($param_value,1,strlen($param_value)-2); 577 578 $items[$param_name] = $param_value; 579 } 580 return $items; 581 } 582 583 584 function getDynamicParameters() 585 { 586 // Fixing old syntax ("key:value") to valid YAML syntax. 587 $this->code = preg_replace( '/^(\w+)\:(.+)$/m','${1}: ${2}', $this->code ); 588 589 $items = \util\YAML::parse( $this->code ); 590 591 Logger::trace('dynamic-parameters: '.print_r($items,true)); 592 593 return (array) $items; 594 } 595 596 597 /** 598 * Ermittelt, ob das Element beschreibbar ist. 599 * Bestimmte Typen (z.B. Info-Felder) sind nie beschreibbar, dann wird immer false zur?ckgegeben. 600 * Ansonsten wird ermittelt, ob dieses Element als beschreibbar markiert ist. 601 */ 602 function isWritable() 603 { 604 // Bei bestimmten Feldern immer false zurueckgeben 605 if ( in_array($this->typeid,Element::$readonlyElementTypeIds) ) 606 return false; 607 608 return $this->writable; 609 } 610 611 612 /** 613 * The technical name of this element type. 614 * 615 * @return String 616 */ 617 public function getTypeName() { 618 return Element::getAvailableTypes()[ $this->typeid ]; // name of type 619 620 } 621 622 public function getName() 623 { 624 return $this->label; 625 } 626 627 628 public function getId() 629 { 630 return $this->elementid; 631 } 632 633 634 }
Download modules/cms/model/Element.class.php
History Wed, 17 Apr 2024 00:34:07 +0200 Jan Dankert New: Inputfields for coordinates; coordinates are stored in the now 64bit-number-field of the value. Thu, 2 Jun 2022 01:04:54 +0200 Jan Dankert New: Element type "checkbox" Wed, 1 Jun 2022 01:05:34 +0200 Jan Dankert New: Element types for "coordinates" and "data" Wed, 1 Jun 2022 00:11:40 +0200 Jan Dankert New: DSL as a filter for number values Wed, 25 May 2022 22:47:17 +0200 Jan Dankert New: DSL (domain specific language) for code elements. The old way with PHP code ist not sandboxed and unsecure. This approach is a minimalistic, javascript-like, scripting engine. For now only simple function calls are possible, for example: alert("example"); Fri, 18 Mar 2022 22:38:42 +0100 dankert Refactoring: Extracted the TemplateGenerator out of the PageGenerator. Mon, 6 Dec 2021 22:33:10 +0100 dankert Some fixes for deleting objects. Fri, 2 Apr 2021 00:12:48 +0200 Jan Dankert New: Valueformat "html source" Sun, 7 Mar 2021 00:10:20 +0100 Jan Dankert Refactoring: Hopefully more performance while accessing the database resultsets. Mon, 26 Oct 2020 23:09:24 +0100 Jan Dankert Cleanup UI for adding templates and adding projects. Fri, 2 Oct 2020 23:11:48 +0200 Jan Dankert Cleanup: No '.inputholder' any more, notices with links to objects. Tue, 29 Sep 2020 22:17:11 +0200 Jan Dankert Refactoring: Do not use global constants. Sat, 26 Sep 2020 04:03:53 +0200 Jan Dankert Refactoring: read language keys with a class. Sat, 26 Sep 2020 02:26:39 +0200 Jan Dankert Refactoring: No global functions any more, the database object is read from the Db class. Wed, 23 Sep 2020 01:04:05 +0200 Jan Dankert Cleanup of deprecated methods and deprecated class attributes. Sun, 23 Feb 2020 04:01:30 +0100 Jan Dankert Refactoring with Namespaces for the cms modules, part 1: moving.