1 <?php 2 /* Copyright (c) 2013, Geert Bergman (geert@scrivo.nl) 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. Neither the name of "Scrivo" nor the names of its contributors may be 14 * used to endorse or promote products derived from this software without 15 * specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $Id: PageDefinition.php 866 2013-08-25 16:22:35Z geert $ 30 */ 31 32 /** 33 * Implementation of the \Scrivo\PageDefinition class. 34 */ 35 36 namespace Scrivo; 37 38 /** 39 * The PageDefinition class is used to create a definition for a page. 40 * 41 * In the Scrivo user interface the editor will select a page definition to 42 * create a page from. The page definition holds a list of configurable 43 * properties (text blocks, images, urls, colors, etc) that can be edited for 44 * that page. See also the class PageDefinitionProperty that is used to define 45 * the individual properties and the class PageDefinitionTab that is used to 46 * distribute these properties over several tabs in the Scrivo user interface. 47 * 48 * Furthermore the page definition holds a reference to the PHP script that 49 * should be executed when rendering pages with this page definition 50 * definition. 51 * 52 * PageDefinitions can be suppressed in the user interface using the 53 * 'configOnly'property: for instance, there is no need to let the editor 54 * chose another page using the 'Home' page definition in a site. Or they can 55 * be shown conditionally in the interface: you can only select pages of page 56 * definition 'Main Menu' as sub pages of a page of page definition 'Home'. 57 * See the 'PageDefinitionHints' class for more details. 58 * 59 * TODO: field type_set now is a semicolon seperated list (DB data), better 60 * to serialize this data. 61 * TODO: field search_index_rule has no function anymore. 62 * 63 * @property-read int $id The page definition id (DB key). 64 * @property-read object $properties The page definition properties. 65 * @property-read \Scrivo\PageDefinitionTab[] $tabs The page definition tabs. 66 * @property boolean $configOnly Setting to suppress this page definition in 67 * the user interface. 68 * @property int $defaultTabId The id of the tab that should be shown in the 69 * user interface as the active tab when the editor selects a page using this 70 * page definition for editing. 71 * @property \Scrivo\String $description An additional description for the 72 * page definition. 73 * @property \Scrivo\String $action The location of the PHP script to 74 * execute when rendering pages using this page definition. 75 * @property \Scrivo\String $title A descriptive title for the page definition. 76 * @property int[] $typeSet The set of page types that the user can select 77 * in the user interface when creating/modifing pages using this page 78 * definition. 79 */ 80 class PageDefinition { 81 82 /** 83 * The page definition id (DB key). 84 * @var int 85 */ 86 private $id = 0; 87 88 /** 89 * A descriptive title for the page definition. 90 * @var \Scrivo\String 91 */ 92 private $title = null; 93 94 /** 95 * An additional description for the page definition. 96 * @var \Scrivo\String 97 */ 98 private $description = null; 99 100 /** 101 * The location of the PHP script to execute when rendering pages using 102 * this page definition. 103 * @var \Scrivo\String 104 */ 105 private $action = null; 106 107 /** 108 * Setting to suppress this page definition in the user interface. 109 * @var boolean 110 */ 111 private $configOnly = false; 112 113 /** 114 * The set of page types that the user can select in the user interface 115 * when creating/modifing pages using this page definition. 116 * @var int[] 117 */ 118 private $typeSet = array(); 119 120 /** 121 * The id of the tab that should be shown in the user interface as the 122 * active tab when the editor selects a page using this page definition 123 * for editing. 124 * @var int 125 */ 126 private $defaultTabId = 0; 127 128 /** 129 * The page definition properties as a PHP object in which the members 130 * correspond with the PHP selector names. 131 * @var \stdClass 132 */ 133 protected $properties = null; 134 135 /** 136 * The page definition tabs. 137 * @var \Scrivo\PageDefinitionTab[] 138 */ 139 protected $tabs = null; 140 141 /** 142 * A Scrivo context. 143 * @var \Scrivo\Context 144 */ 145 private $context = null; 146 147 /** 148 * Create an empty page definition object. 149 * 150 * @param \Scrivo\Context $context A Scrivo context. 151 */ 152 public function __construct(\Scrivo\Context $context=null) { 153 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array(null), 0); 154 155 if ($context) { 156 $this->title = new \Scrivo\String(); 157 $this->description = new \Scrivo\String(); 158 $this->action = new \Scrivo\String(); 159 160 $this->context = $context; 161 } 162 } 163 164 /** 165 * Implementation of the readable properties using the PHP magic 166 * method __get(). 167 * 168 * @param string $name The name of the property to get. 169 * 170 * @return mixed The value of the requested property. 171 */ 172 public function __get($name) { 173 switch($name) { 174 case "id": return $this->id; 175 case "title": return $this->title; 176 case "description": return $this->description; 177 case "action": return $this->action; 178 case "configOnly": return $this->configOnly; 179 case "typeSet": return $this->typeSet; 180 case "defaultTabId": return $this->defaultTabId; 181 case "properties": return $this->getProperties(); 182 case "tabs": return $this->getTabs(); 183 } 184 throw new \Scrivo\SystemException("No such get-property '$name'."); 185 } 186 187 /** 188 * Implementation of the writable properties using the PHP magic 189 * method __set(). 190 * 191 * @param string $name The name of the property to set. 192 * @param mixed $value The value of the property to set. 193 */ 194 public function __set($name, $value) { 195 switch($name) { 196 case "title": $this->setTitle($value); return; 197 case "description": $this->setDescription($value); return; 198 case "action": $this->setFileName($value); return; 199 case "configOnly": $this->setConfigOnly($value); return; 200 case "typeSet": $this->setTypeSet($value); return; 201 case "defaultTabId": $this->setDefaultTabId($value); return; 202 } 203 throw new \Scrivo\SystemException("No such set-property '$name'."); 204 } 205 206 /** 207 * Convenience method to set the fields of a page definition object from 208 * an array (result set row). 209 * 210 * @param \Scrivo\Context $context A Scrivo context. 211 * @param array $rd An array containing the field data using the database 212 * field names as keys. 213 */ 214 private function setFields(\Scrivo\Context $context, array $rd) { 215 216 $this->id = intval($rd["page_definition_id"]); 217 $this->title = new \Scrivo\String($rd["title"]); 218 $this->description = new \Scrivo\String($rd["description"]); 219 $this->action = new \Scrivo\String($rd["action"]); 220 $this->configOnly = intval($rd["config_only"]) == 1 ? true : false; 221 $this->typeSet = 222 $this->convertTypeSet(new \Scrivo\String($rd["type_set"])); 223 $this->defaultTabId = intval($rd["default_tab_id"]); 224 225 $this->context = $context; 226 } 227 228 /** 229 * Get this page definition's property list. 230 * 231 * @return object This page definition's property list. 232 */ 233 private function getProperties() { 234 if ($this->properties === null) { 235 $this->properties = (object) 236 \Scrivo\PagePropertyDefinition::select($this->context, $this->id); 237 } 238 return $this->properties; 239 } 240 241 /** 242 * Get this page definition's tabs. 243 * 244 * @return \Scrivo\PageDefinitionTab[] This page definition's tabs. 245 */ 246 private function getTabs() { 247 if ($this->tabs === null) { 248 $this->tabs = 249 \Scrivo\PageDefinitionTab::select($this->context, $this->id); 250 } 251 return $this->tabs; 252 } 253 254 /** 255 * Set A descriptive title for the page definition. 256 * 257 * @param \Scrivo\String $title A descriptive title for the page 258 * definition. 259 */ 260 private function setTitle(\Scrivo\String $title) { 261 $this->title = $title; 262 } 263 264 /** 265 * Set the additional description for the page definition. 266 * 267 * @param \Scrivo\String $description An additional description for the 268 * page definition. 269 */ 270 private function setDescription(\Scrivo\String $description) { 271 $this->description = $description; 272 } 273 274 /** 275 * Set the location of the PHP script to execute when rendering pages 276 * using this page definition. 277 * 278 * @param \Scrivo\String $action The location of the PHP script to 279 * execute when rendering pages using this page definition. 280 */ 281 private function setFileName(\Scrivo\String $action) { 282 $this->action = $action; 283 } 284 285 /** 286 * Set the setting to suppress this page definition in the user interface. 287 * 288 * @param boolean $configOnly Setting to suppress this page definition in 289 * the user interface. 290 */ 291 private function setConfigOnly($configOnly) { 292 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 293 array(\Scrivo\ArgumentCheck::TYPE_BOOLEAN) 294 )); 295 296 $this->configOnly = $configOnly; 297 } 298 299 /** 300 * Set the set of page types that the user can select in the user interface 301 * when creating/modifing pages using this page definition. 302 * 303 * @param int[] $typeSet The set of page types that the user can select in 304 * the user interface when creating/modifing pages using this page 305 * definition. 306 */ 307 private function setTypeSet(array $typeSet) { 308 $this->typeSet = $typeSet; 309 } 310 311 /** 312 * Set the id of the tab that should be shown in the user interface as 313 * the active tab when the editor selects a page using this page definition 314 * for editing. 315 * 316 * @param int $defaultTabId The id of the tab that should be shown in the 317 * user interface as the active tab when the editor selects a page using 318 * this page definition for editing. 319 */ 320 private function setDefaultTabId($defaultTabId) { 321 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 322 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 323 )); 324 325 $this->defaultTabId = $defaultTabId; 326 } 327 328 /** 329 * Convert the semicolon seperated value from the database to an array. 330 * 331 * @param \Scrivo\String typeSetString An semicolon seperated string. 332 * @return int[] The type set as an array of integers. 333 */ 334 private function convertTypeSet(\Scrivo\String $typeSetString) { 335 $ts = $typeSetString->split(new \Scrivo\String(";")); 336 $ts2 = array(); 337 foreach ($ts as $pageId) { 338 $ts2[] = intval((string)$pageId); 339 } 340 return $ts2; 341 } 342 343 /** 344 * Check if this page definition object can be inserted into the database. 345 * 346 * @throws \Scrivo\ApplicationException If the data is not accessible or 347 * one or more of the fields contain invalid data. 348 */ 349 private function validateInsert() { 350 $this->context->checkPermission(\Scrivo\AccessController::WRITE_ACCESS); 351 } 352 353 /** 354 * Insert new page definition object data into the database. 355 * 356 * First it is checked if the data of this page definition object can be 357 * inserted into the database, then the data is inserted into the database. 358 * If no id was set a new object id is generated. 359 * 360 * @throws \Scrivo\ApplicationException If the data is not accessible or 361 * one or more of the fields contain invalid data. 362 */ 363 public function insert() { 364 try { 365 $this->validateInsert(); 366 367 if (!$this->id) { 368 $this->id = $this->context->connection->generateId(); 369 } 370 371 $sth = $this->context->connection->prepare( 372 "INSERT INTO page_definition ( 373 instance_id, page_definition_id, title, description, action, 374 config_only, type_set, default_tab_id 375 ) VALUES ( 376 :instId, :id, :title, :description, :action, 377 :configOnly, :typeSet, :defaultTabId 378 )"); 379 380 $this->context->connection->bindInstance($sth); 381 $sth->bindValue(":id", $this->id, \PDO::PARAM_INT); 382 $sth->bindValue(":title", $this->title, \PDO::PARAM_STR); 383 $sth->bindValue( 384 ":description", $this->description, \PDO::PARAM_STR); 385 $sth->bindValue(":action", $this->action, \PDO::PARAM_STR); 386 $sth->bindValue(":configOnly", 387 $this->configOnly ? 1 : 0, \PDO::PARAM_INT); 388 $sth->bindValue(":typeSet", new \Scrivo\String( 389 implode(";", $this->typeSet)), \PDO::PARAM_INT); 390 $sth->bindValue( 391 ":defaultTabId", $this->defaultTabId, \PDO::PARAM_INT); 392 393 $sth->execute(); 394 395 } catch(\PDOException $e) { 396 throw new \Scrivo\ResourceException($e); 397 } 398 } 399 400 /** 401 * Check if this page definition object can be updated in the database. 402 * 403 * @throws \Scrivo\ApplicationException If the data is not accessible or 404 * one or more of the fields contain invalid data. 405 */ 406 private function validateUpdate() { 407 $this->context->checkPermission(\Scrivo\AccessController::WRITE_ACCESS); 408 } 409 410 /** 411 * Update existing page definition object data in the database. 412 * 413 * First it is checked if the data of this page definition object can be 414 * updated in the database, then the data is updated in the database. 415 * 416 * @throws \Scrivo\ApplicationException If the data is not accessible or 417 * one or more of the fields contain invalid data. 418 */ 419 public function update() { 420 try { 421 $this->validateUpdate(); 422 423 $sth = $this->context->connection->prepare( 424 "UPDATE page_definition SET 425 title = :title, description = :description, 426 action = :action, config_only = :configOnly, 427 type_set = :typeSet, default_tab_id = :defaultTabId 428 WHERE instance_id = :instId AND page_definition_id = :id"); 429 430 $this->context->connection->bindInstance($sth); 431 $sth->bindValue(":id", $this->id, \PDO::PARAM_INT); 432 433 $sth->bindValue(":title", $this->title, \PDO::PARAM_STR); 434 $sth->bindValue( 435 ":description", $this->description, \PDO::PARAM_STR); 436 $sth->bindValue(":action", $this->action, \PDO::PARAM_STR); 437 $sth->bindValue(":configOnly", 438 $this->configOnly ? 1 : 0, \PDO::PARAM_INT); 439 $sth->bindValue(":typeSet", new \Scrivo\String( 440 implode(";", $this->typeSet)), \PDO::PARAM_INT); 441 $sth->bindValue( 442 ":defaultTabId", $this->defaultTabId, \PDO::PARAM_INT); 443 444 $sth->execute(); 445 446 unset($this->context->cache[$this->id]); 447 448 } catch(\PDOException $e) { 449 throw new \Scrivo\ResourceException($e); 450 } 451 } 452 453 /** 454 * Check if deletion of page definition object data does not violate any 455 * business rules. 456 * 457 * @param \Scrivo\Context $context A Scrivo context. 458 * @param int $id The object id of the page definition to select. 459 * 460 * @throws \Scrivo\ApplicationException If the data is not accessible or 461 * if it is not possible to delete the language data. 462 */ 463 private static function validateDelete(\Scrivo\Context $context, $id) { 464 $context->checkPermission(\Scrivo\AccessController::WRITE_ACCESS); 465 } 466 467 /** 468 * Delete existing page definition data from the database. 469 * 470 * First it is is checked if it's possible to delete page definition data, 471 * then the page definition data including its dependencies is deleted from 472 * the database. 473 * 474 * @param \Scrivo\Context $context A Scrivo context. 475 * @param int $id The object id of the page definition to select. 476 * 477 * @throws \Scrivo\ApplicationException If the data is not accessible or 478 * if it is not possible to delete the page definition data. 479 */ 480 public static function delete(\Scrivo\Context $context, $id) { 481 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 482 null, 483 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 484 )); 485 try { 486 self::validateDelete($context, $id); 487 488 foreach (array("page_property_definition", "page_definition_tab", "page_definition") 489 as $table) { 490 491 $sth = $context->connection->prepare( 492 "DELETE FROM $table 493 WHERE instance_id = :instId AND page_definition_id = :id"); 494 495 $context->connection->bindInstance($sth); 496 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 497 498 $sth->execute(); 499 } 500 501 unset($context->cache[$id]); 502 503 } catch(\PDOException $e) { 504 throw new \Scrivo\ResourceException($e); 505 } 506 } 507 508 /** 509 * Fetch a page definition object from the database using its object id. 510 * 511 * @param \Scrivo\Context $context A Scrivo context. 512 * @param int $id The object id of the page definition to select. 513 * 514 * @return \Scrivo\PageDefinition The requested page definition object. 515 */ 516 public static function fetch(\Scrivo\Context $context, $id) { 517 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 518 null, 519 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 520 )); 521 try { 522 // Try to retieve the page definition from the cache ... 523 if (isset($context->cache[$id])) { 524 // ... get it from the cache and set the context. 525 $pageDefinition = $context->cache[$id]; 526 $pageDefinition->context = $context; 527 } else { 528 // ... else retrieve it and set it in the cache. 529 $sth = $context->connection->prepare( 530 "SELECT page_definition_id, title, description, action, 531 config_only, type_set, default_tab_id 532 FROM page_definition 533 WHERE instance_id = :instId AND page_definition_id = :id"); 534 535 $context->connection->bindInstance($sth); 536 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 537 538 $sth->execute(); 539 540 if ($sth->rowCount() != 1) { 541 throw new \Scrivo\SystemException( 542 "Failed to load page definition $id"); 543 } 544 545 $pageDefinition = new \Scrivo\PageDefinition(); 546 $pageDefinition->setFields( 547 $context, $sth->fetch(\PDO::FETCH_ASSOC)); 548 549 $context->cache[$id] = $pageDefinition; 550 } 551 552 return $pageDefinition; 553 554 } catch(\PDOException $e) { 555 throw new \Scrivo\ResourceException($e); 556 } 557 } 558 559 /** 560 * Select page definitions from the database. 561 * 562 * @param \Scrivo\Context $context A Scrivo context. 563 * 564 * @return \Scrivo\PageDefinition[id] An array containing the selected 565 * page definitions. 566 */ 567 public static function select(\Scrivo\Context $context) { 568 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array(null)); 569 try { 570 $sth = $context->connection->prepare( 571 "SELECT page_definition_id, title, description, action, 572 config_only, type_set, default_tab_id 573 FROM page_definition 574 WHERE instance_id = :instId 575 ORDER BY title"); 576 577 $context->connection->bindInstance($sth); 578 579 $sth->execute(); 580 581 $res = array(); 582 583 while ($rd = $sth->fetch(\PDO::FETCH_ASSOC)) { 584 585 $li = new PageDefinition(); 586 $li->setFields($context, $rd); 587 588 $res[$li->id] = $li; 589 } 590 591 return $res; 592 593 } catch(\PDOException $e) { 594 throw new \Scrivo\ResourceException($e); 595 } 596 } 597 598 /** 599 * Select the list of page definitions that are selectable by a an editor. 600 * 601 * @param \Scrivo\Context $context A Scrivo context. 602 * @param int $parentId The id of the page where the editor wants to 603 * create a page underneath. 604 * 605 * @return PageDefinition[id] An array containing the selected page 606 * definitions. 607 */ 608 public static function selectSelectable( 609 \Scrivo\Context $context, $parentId) { 610 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 611 null, 612 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 613 )); 614 615 // Select all the page definitions ... 616 $list = self::select($context); 617 618 // ... and the hints ... 619 $hints = new \Scrivo\PageDefinitionHints($context, $parentId, 620 \Scrivo\PageDefinitionHints::CHILD_PAGE_DEFINITION_REMAINING); 621 622 // ... and create a new list of page definitions that are not config 623 // only and have a count left according the hints list. 624 $pageDefinitions = array(); 625 foreach ($list as $k=>$pageDef) { 626 if (!$pageDef->configOnly && $hints[$k]->maxNoOfChildren !== 0) { 627 $pageDefinitions[$k] = $pageDef; 628 } 629 } 630 631 return $pageDefinitions; 632 } 633 634 } 635 636 ?>
Documentation generated by phpDocumentor 2.0.0a12 and ScrivoDocumentor on August 29, 2013