1 <?php 2 /* Copyright (c) 2012, 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: ItemList.php 866 2013-08-25 16:22:35Z geert $ 30 */ 31 32 /** 33 * Implementation of the \Scrivo\ItemList class. 34 */ 35 36 namespace Scrivo; 37 38 /** 39 * Item lists (or Scrivo list) are a very versitle way of adding list like 40 * data to a page (faq, comments, news and even a forurm like) 41 */ 42 class ItemList { 43 44 /** 45 * The list/application id (DB key). 46 * @var int 47 */ 48 private $id = 0; 49 50 /** 51 * Id of the list definition. 52 * @var int 53 */ 54 private $pagePropertyDefinitionId = 0; 55 56 /** 57 * Id of the application definition. 58 * @var int 59 */ 60 private $applicationDefinitionId = 0; 61 62 /** 63 * Id of the page where this list instance is associated with. 64 * @var int 65 */ 66 private $pageId = 0; 67 68 /** 69 * Optional reference to a page that is parent for pages linked to 70 * list items. 71 * @var int 72 */ 73 private $folderId = 0; 74 75 /** 76 * A list of list item pids. 77 * @var array[] 78 */ 79 private $listPids = null; 80 81 /** 82 * The attached roles. 83 * @var \Scrivo\RoleSet 84 */ 85 private $roles; 86 87 /** 88 * A Scrivo context. 89 * @var \Scrivo\Context 90 */ 91 private $context = null; 92 93 /** 94 * Construct an item list. Item lists are Scrivo application and therefore 95 * linked to a page and an application definition. 96 * 97 * Scrivo lists are never created as explicitly, but assumed to exist if 98 * a page with a list type application definition does exist. If not the 99 * list is created on the fly based upon its defintion. Because actual 100 * list creation is an internal issue and not ment to do expicitly the 101 * constructor is not public. 102 * 103 * To create a list see 'fetch'. 104 * 105 * @param \Scrivo\Context $context A valid Scrivo context 106 * @param string $pageId The id of the page that hosts the application. 107 * @param string $pagePropertyDefinitionId The page property definition id. 108 */ 109 protected function __construct( 110 \Scrivo\Context $context, $pageId, $pagePropertyDefinitionId) { 111 try { 112 $this->context = $context; 113 114 // Check if the list was create before (the list record exists). 115 $sth = $context->connection->prepare( 116 "SELECT L.item_list_id, L.page_definition_tab_id, L.page_id, 117 L.folder_id, T.application_definition_id 118 FROM item_list L, page_definition_tab T, page D 119 WHERE L.instance_id = :instId AND D.instance_id = :instId AND 120 T.instance_id = :instId AND D.page_definition_id = T.page_definition_id AND 121 T.page_definition_tab_id = L.page_definition_tab_id AND 122 L.version = D.version AND L.page_id = D.page_id AND 123 (D.has_staging + D.version) = 0 AND 124 L.page_definition_tab_id = :ppDefId AND 125 L.page_id = :pageId"); 126 127 $context->connection->bindInstance($sth); 128 $sth->bindValue(":pageId", $pageId, \PDO::PARAM_INT); 129 $sth->bindValue( 130 ":ppDefId", $pagePropertyDefinitionId, \PDO::PARAM_INT); 131 132 $sth->execute(); 133 134 if ($sth->rowCount() > 1) { 135 throw new \Scrivo\SystemException( 136 "Data corruption: failed to load list"); 137 } else if ($sth->rowCount() === 0) { 138 // If not create it 139 // Is it a valid page and application definition 140 // Yes create the list 141 // else throw up 142 $this->pageId = $pageId; 143 $this->pagePropertyDefinitionId = $pagePropertyDefinitionId; 144 $this->insert(); 145 } else { 146 $rd = $sth->fetch(\PDO::FETCH_ASSOC); 147 $this->id = intval($rd["item_list_id"]); 148 $this->pagePropertyDefinitionId = 149 intval($rd["page_definition_tab_id"]); 150 $this->pageId = intval($rd["page_id"]); 151 $this->folderId = intval($rd["folder_id"]); 152 $this->applicationDefinitionId = intval($rd["application_definition_id"]); 153 } 154 155 // Select it 156 157 // TODO: when the list definition chances and a sub-folder is 158 // required mark this in the list item definition (HAS_FOLDER or 159 // something like that). Then is it is easliy decided if the sub 160 // folder needs to be created at this point. 161 // Or delegate it to list item creation. 162 163 // "Borrow" the read access roles form the host page. 164 $this->roles = new \Scrivo\RoleSet(); 165 166 $sth = $context->connection->prepare( 167 "SELECT role_id FROM object_role 168 WHERE instance_id = :instId AND page_id = :pageId"); 169 170 $context->connection->bindInstance($sth); 171 $sth->bindValue(":pageId", $pageId, \PDO::PARAM_INT); 172 173 $sth->execute(); 174 175 while ($rd = $sth->fetch(\PDO::FETCH_ASSOC)) { 176 $this->roles[] = intval($rd["role_id"]); 177 } 178 179 $this->listPids = array(); 180 181 } catch(\PDOException $e) { 182 throw new \Scrivo\ResourceException($e); 183 } 184 } 185 186 /** 187 * Implementation of the readable properties using the PHP magic 188 * method __get(). 189 * 190 * @param string $name The name of the property to get. 191 * 192 * @return mixed The value of the requested property. 193 */ 194 public function __get($name) { 195 switch($name) { 196 case "items": return $this->getItems(0); 197 } 198 throw new \Scrivo\SystemException("No such get-property '$name'."); 199 } 200 201 /** 202 * Insert new list object data into the database. A list record is assumed 203 * to exists if page exists and is created silently. 204 * 205 * @throws \Scrivo\ApplicationException If the data is not accessible or 206 * one or more of the fields contain invalid data. 207 */ 208 private function insert() { 209 210 $this->id = $this->context->connection->generateId(); 211 212 $sth = $this->context->connection->prepare( 213 "INSERT INTO item_list ( 214 instance_id, item_list_id, page_definition_tab_id, page_id, 215 version, folder_id 216 ) VALUES ( 217 :instId, :id, :pagePropDefId, :pageId, 218 0, :folderId 219 )"); 220 221 $this->context->connection->bindInstance($sth); 222 $sth->bindValue(":id", $this->id, \PDO::PARAM_INT); 223 $sth->bindValue( 224 ":pagePropDefId", $this->pagePropertyDefinitionId, \PDO::PARAM_INT); 225 $sth->bindValue(":pageId", $this->pageId, \PDO::PARAM_INT); 226 $sth->bindValue(":folderId", $this->folderId, \PDO::PARAM_INT); 227 228 $sth->execute(); 229 230 } 231 232 /** 233 * Update list object data in the database. Only used to set the subfolder 234 * id. 235 * 236 * @throws \Scrivo\ApplicationException If the data is not accessible or 237 * one or more of the fields contain invalid data. 238 */ 239 private function update() { 240 241 $sth = $this->context->connection->prepare( 242 "UPDATE item_list SET folder_id = :folderId 243 WHERE instance_id = :instId AND item_list_id = :listId"); 244 245 $this->context->connection->bindInstance($sth); 246 $sth->bindValue(":folderId", $this->folderId, \PDO::PARAM_INT); 247 $sth->bindValue(":listId", $this->id, \PDO::PARAM_INT); 248 249 $sth->execute(); 250 251 } 252 253 /** 254 * Retrieve an item list from the cache or database. 255 * 256 * @param \Scrivo\Context $context A Scrivo context. 257 * @param int $pageId The id of the page that hosts the list. 258 * @param int $defintionId The id of the page property definition. 259 * 260 * @throws \Scrivo\ApplicationException if the page was not readable for 261 * the user defined in the context. 262 */ 263 public static function fetch(\Scrivo\Context $context, $pageId, $defintionId) { 264 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 265 null, 266 array(\Scrivo\ArgumentCheck::TYPE_INTEGER), 267 array(\Scrivo\ArgumentCheck::TYPE_INTEGER), 268 )); 269 270 // Try to retieve form cache 271 $obj = null; 272 $cId = "$pageId.$defintionId"; 273 if (isset($context->cache[$cId])) { 274 // Get the list from cache and set the context. 275 $obj = $context->cache[$cId]; 276 $obj->context = $context; 277 } else { 278 // Load the list and set it in the cache. 279 $obj = new \Scrivo\ItemList($context, $pageId, $defintionId); 280 $context->cache[$cId] = $obj; 281 } 282 $obj->roles->checkReadPermission($context->principal); 283 return $obj; 284 } 285 286 /** 287 * Retrieve all list items at root level. 288 * 289 * @return \Scrivo\ListItem[] An array if list items. 290 public function getItems() { 291 $res = $this->list[0]; 292 return $res ? $res : array(); 293 } 294 */ 295 296 /** 297 * Retrieve a sub list. 298 * 299 * @param int $parentId The id of the common parent for the list items. 300 * 301 * @return \Scrivo\ListItem[] An array if list items. 302 */ 303 public function getItems($parentId) { 304 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 305 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 306 )); 307 308 \Scrivo\ArgumentCheck::assert( 309 $parentId, \Scrivo\ArgumentCheck::TYPE_INTEGER); 310 return $this->select($parentId); 311 } 312 313 /** 314 * Select list items from the database. 315 * 316 * @param int $parentId An optional parent id is case of a sub-list. 317 * 318 * @return \Scrivo\ListItem[id] An array containing the selected list items. 319 */ 320 private function select($parentId=0) { 321 322 $cId = $this->pageId . "." . $this->pagePropertyDefinitionId; 323 324 if (!isset($this->listPids[$parentId])) { 325 $this->listPids[$parentId] = true; 326 $this->context->cache[$cId] = $this; 327 328 } 329 330 if (isset($this->context->cache[$cId . "." . $parentId])) { 331 return $this->context->cache[$cId . "." . $parentId]; 332 } 333 334 try { 335 $sth = $this->context->connection->prepare( 336 "SELECT I.list_item_id, I.item_list_id, I.link_id, 337 I.version, I.parent_id, I.sequence_no, I.list_item_definition_id, 338 I.page_id, I.title, I.date_created, I.date_modified, I.date_online, 339 I.date_offline 340 FROM list_item I, item_list L 341 WHERE I.instance_id = :instId AND L.instance_id = :instId 342 AND L.item_list_id = I.item_list_id 343 AND I.parent_id = :parentId 344 AND L.page_id = :pageId 345 AND L.page_definition_tab_id = :defId 346 AND L.version = 0 AND I.version = 0 347 ORDER BY parent_id, sequence_no"); 348 349 $this->context->connection->bindInstance($sth); 350 $sth->bindValue(":pageId", $this->pageId, \PDO::PARAM_INT); 351 $sth->bindValue(":parentId", $parentId, \PDO::PARAM_INT); 352 $sth->bindValue( 353 ":defId", $this->pagePropertyDefinitionId, \PDO::PARAM_INT); 354 355 $sth->execute(); 356 357 $res = array(); 358 $prps = null; 359 360 while ($rd = $sth->fetch(\PDO::FETCH_ASSOC)) { 361 362 // TODO: get this out of the loop, its here because of the 363 // list id 364 if ($prps === null) { 365 $prps = self::selectProperties( 366 $this->context, intval($rd["item_list_id"])); 367 } 368 369 $id = intval($rd["list_item_id"]); 370 371 $li = new \Scrivo\ListItem($rd, 372 isset($prps[$id]) ? $prps[$id] : new \Scrivo\PropertySet()); 373 374 $res[$li->id] = $li; 375 } 376 377 $this->context->cache[$cId . "." . $parentId] = $res; 378 379 return $res; 380 381 } catch(\PDOException $e) { 382 throw new \Scrivo\ResourceException($e); 383 } 384 } 385 386 /** 387 * Select list item properties from the database. 388 * 389 * @param \Scrivo\Context $context A Scrivo context. 390 * @param int $listId The id of the list for which to retrieve the 391 * properties. 392 * 393 * @return ListItemProperty[type] An array containing the selected list 394 * item properties. 395 */ 396 private static function selectProperties(\Scrivo\Context $context, 397 $listId) { 398 399 $sth = $context->connection->prepare( 400 "SELECT I.list_item_id, I.page_id, 401 T.list_item_property_definition_id ID_DEF, T.type, T.php_key, 402 IFNULL(V.value, '') value 403 FROM 404 list_item I 405 JOIN list_item_property_definition T ON ( 406 I.instance_id = :instId AND T.instance_id = :instId 407 AND I.list_item_definition_id = T.list_item_definition_id) 408 LEFT JOIN list_item_property V ON ( 409 V.instance_id = :instId AND I.instance_id = :instId 410 AND T.instance_id = :instId 411 AND V.list_item_property_definition_id = T.list_item_property_definition_id 412 AND V.list_item_id = I.list_item_id AND V.version = 0) 413 WHERE 414 I.instance_id = :instId 415 AND I.item_list_id = :listId AND I.version = 0" 416 // .($itemId ? " AND I.list_item_id = :itemId" : "") 417 ); 418 419 $context->connection->bindInstance($sth); 420 $sth->bindValue(":listId", $listId, \PDO::PARAM_INT); 421 /* 422 if ($itemId) { 423 $sth->bindValue(":itemId", $itemId, \PDO::PARAM_INT); 424 } 425 */ 426 $sth->execute(); 427 428 $res = array(); 429 $id = -1; 430 431 while ($rd = $sth->fetch(\PDO::FETCH_ASSOC)) { 432 433 $lid = intval($rd["list_item_id"]); 434 435 if ($lid != $id) { 436 $id = $lid; 437 $res[$id] = new \Scrivo\PropertySet(); 438 } 439 440 $li = ListItemProperty::create($rd); 441 442 if ($li && !$li->phpSelector->equals(new \Scrivo\String(""))) { 443 $res[$id]->{$li->phpSelector} = $li; 444 } 445 } 446 447 return $res; 448 } 449 450 /** 451 * Create a linked page for a list item. 452 * 453 * @param \Scrivo\ListItem $item The list item for which to create the 454 * linked page. 455 * @param \Scrivo\ListItemDefinition $def The list item defintion of the 456 * list item for which to create the linked page. 457 * 458 * @return int The page id of the page to link. 459 */ 460 private function createLinkedPage( 461 \Scrivo\ListItem $item, \Scrivo\ListItemDefinition $def) { 462 463 // Load the reference page to copy the language and role settings. 464 $mp = \Scrivo\Page::fetch($this->context, $this->pageId); 465 466 // If no subfolder exists yet create one. 467 if (!$this->folderId) { 468 469 $propDef = \Scrivo\PagePropertyDefinition::fetch( 470 $this->context, $this->pagePropertyDefinitionId); 471 $tab = \Scrivo\PageDefinitionTab::fetch( 472 $this->context, $propDef->pageDefinitionTabId); 473 474 $folder = new \Scrivo\Page($this->context); 475 $folder->parentId = $this->pageId; 476 $folder->type = \Scrivo\Page::TYPE_SUB_FOLDER; 477 $folder->title = $tab->title; 478 $folder->insert(); 479 480 $this->folderId = $folder->id; 481 $this->update(); 482 } 483 484 // Create the sub-page. 485 $sub = new \Scrivo\Page($this->context); 486 $sub->definitionId = $def->pageDefinitionId; 487 $sub->parentId = $this->folderId; 488 $sub->type = \Scrivo\Page::TYPE_NON_NAVIGABLE_PAGE; 489 $sub->title = $item->title; 490 $sub->insert(); 491 492 return $sub->id; 493 } 494 495 /** 496 * Get the list item definition id using the phpSelector of the list 497 * item definition. 498 * 499 * @param \Scrivo\String $phpSelector The phpSelector of a list 500 * item definition. 501 * 502 * @return int The list item definition id. 503 */ 504 private function getDefinitionId(\Scrivo\String $phpSelector) { 505 506 $sth = $this->context->connection->prepare( 507 "SELECT T.list_item_definition_id FROM list_item_definition T WHERE 508 T.instance_id = :instId AND T.application_definition_id = :appDefId AND 509 T.php_key = :sel"); 510 511 $this->context->connection->bindInstance($sth); 512 $sth->bindValue( 513 ":appDefId", $this->applicationDefinitionId, \PDO::PARAM_INT); 514 $sth->bindValue(":sel", $phpSelector, \PDO::PARAM_STR); 515 516 $sth->execute(); 517 518 return intval($sth->fetchColumn()); 519 } 520 521 /** 522 * Create a set of blank properties for a given list item definition. 523 * 524 * @param int $definitionId 525 * 526 * @return \Scrivo\PropertySet 527 */ 528 private function selectEmptyProperties($definitionId) { 529 530 $sth = $this->context->connection->prepare( 531 "SELECT 532 0 list_item_id, null value, :pageId page_id, 533 list_item_property_definition_id ID_DEF, type, php_key 534 FROM list_item_property_definition 535 WHERE instance_id = :instId AND list_item_definition_id = :sel"); 536 537 $this->context->connection->bindInstance($sth); 538 $sth->bindValue(":pageId", $this->pageId, \PDO::PARAM_INT); 539 $sth->bindValue(":sel", $definitionId, \PDO::PARAM_INT); 540 541 $sth->execute(); 542 543 $res = new \Scrivo\PropertySet(); 544 545 while ($rd = $sth->fetch(\PDO::FETCH_ASSOC)) { 546 547 $li = ListItemProperty::create($rd); 548 549 if ($li && !$li->phpSelector->equals(new \Scrivo\String(""))) { 550 $res->{$li->phpSelector} = $li; 551 } 552 } 553 554 return $res; 555 } 556 557 /** 558 * Update an existing list item property in the database. 559 * 560 * First the data fields of this user will be validated, then the data 561 * is updated in the database. 562 * 563 * @param \Scrivo\ListItemProperty $prp The list item property to update. 564 * @param int $itemId The id of the list item for which to update the 565 * property. 566 * 567 * @throws \Scrivo\ApplicationException If one or more of the fields 568 * contain invalid data. 569 */ 570 private function updateProperty(\Scrivo\ListItemProperty $prp, $itemId) { 571 572 $sth = $this->context->connection->prepare( 573 "DELETE FROM list_item_property WHERE instance_id = :instId AND 574 list_item_id = :listItemId AND list_item_property_definition_id = :idDef AND 575 version = 0"); 576 577 $this->context->connection->bindInstance($sth); 578 $sth->bindValue(":listItemId", $itemId, \PDO::PARAM_INT); 579 $sth->bindValue(":idDef", $prp->definitionId, \PDO::PARAM_STR); 580 581 $sth->execute(); 582 583 $sth = $this->context->connection->prepare( 584 "INSERT INTO list_item_property ( 585 instance_id, list_item_id, version, list_item_property_definition_id, 586 page_id, value 587 ) VALUES (:instId, :listItemId, 0, :idDef, :pageId, :data)"); 588 589 $this->context->connection->bindInstance($sth); 590 $sth->bindValue(":listItemId", $itemId, \PDO::PARAM_INT); 591 $sth->bindValue(":idDef", $prp->definitionId, \PDO::PARAM_STR); 592 $sth->bindValue(":pageId", $prp->pageId, \PDO::PARAM_STR); 593 $sth->bindValue(":data", $prp->data, \PDO::PARAM_STR); 594 595 $sth->execute(); 596 } 597 598 /** 599 * Insert new list item object data into the database. 600 * 601 * First it is checked if the data of this list item object can be inserted 602 * into the database, then the data is inserted into the database. If no id 603 * was set a new object id is generated. 604 * 605 * @param \Scrivo\ListItem $item The list item to insert into the database. 606 * 607 * @throws \Scrivo\ApplicationException If the data is not accessible or 608 * one or more of the fields contain invalid data. 609 */ 610 private function insertItem(\Scrivo\ListItem $item) { 611 612 // Create a sub-page if necessary 613 $def = \Scrivo\ListItemDefinition::fetch( 614 $this->context, $item->definitionId); 615 $linkedPageId = 0; 616 if ($def->pageDefinitionId) { 617 $linkedPageId = $this->createLinkedPage($item, $def); 618 } 619 620 $id = $this->context->connection->generateId(); 621 622 $sth = $this->context->connection->prepare( 623 "INSERT INTO list_item ( 624 instance_id, list_item_id, item_list_id, link_id, 625 version, parent_id, sequence_no, list_item_definition_id, 626 page_id, title, date_created, date_modified, 627 date_online, date_offline 628 ) VALUES ( 629 :instId, :id, :listId, :pageId, 630 :version, :parentId, :sequenceNo, :definitionId, 631 :linkedPageId, :title, now(), now(), 632 :dateOnline, :dateOffline 633 )"); 634 635 $this->context->connection->bindInstance($sth); 636 637 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 638 $sth->bindValue(":listId", $item->listId, \PDO::PARAM_INT); 639 $sth->bindValue(":pageId", $item->pageId, \PDO::PARAM_INT); 640 $sth->bindValue(":version", $item->version, \PDO::PARAM_INT); 641 $sth->bindValue(":parentId", $item->parentId, \PDO::PARAM_INT); 642 $sth->bindValue(":sequenceNo", 0, \PDO::PARAM_INT); 643 $sth->bindValue(":definitionId", 644 $item->definitionId, \PDO::PARAM_INT); 645 // TODO: no item-> ??? 646 $sth->bindValue(":linkedPageId", $linkedPageId, \PDO::PARAM_INT); 647 $sth->bindValue(":title", $item->title, \PDO::PARAM_STR); 648 $sth->bindValue(":dateOnline", 649 $item->dateOnline->format("Y-m-d H:i:s"), \PDO::PARAM_STR); 650 $sth->bindValue(":dateOffline", $item->dateOffline 651 ? $item->dateOffline->format("Y-m-d H:i:s") 652 : null, \PDO::PARAM_STR); 653 654 $sth->execute(); 655 656 foreach ($item->properties as $prp) { 657 $this->updateProperty($prp, $id); 658 } 659 660 \Scrivo\SequenceNo::position($this->context, "list_item", 661 array("parent_id", "item_list_id"), $id, \Scrivo\SequenceNo::MOVE_FIRST); 662 663 } 664 665 /** 666 * Update existing list item object data in the database. 667 * 668 * First it is checked if the data of this list item object can be updated 669 * in the database, then the data is updated in the database. 670 * 671 * @param \Scrivo\ListItem $item The list item to update in the database. 672 * 673 * @throws \Scrivo\ApplicationException If the data is not accessible or 674 * one or more of the fields contain invalid data. 675 */ 676 private function updateItem(\Scrivo\ListItem $item) { 677 678 // Create a sub-page if necessary 679 $def = \Scrivo\ListItemDefinition::fetch( 680 $this->context, $item->definitionId); 681 $linkedPageId = $item->linkedPageId; 682 if (!$linkedPageId && $def->pageDefinitionId) { 683 $linkedPageId = $this->createLinkedPage($item, $def); 684 } 685 686 $sth = $this->context->connection->prepare( 687 "UPDATE list_item SET 688 parent_id = :parentId, title = :title, link_id = :linkedPage, 689 date_online = :dateOnline, date_offline = :dateOffline 690 WHERE instance_id = :instId AND list_item_id = :id"); 691 692 $this->context->connection->bindInstance($sth); 693 $sth->bindValue(":id", $item->id, \PDO::PARAM_INT); 694 695 $sth->bindValue(":parentId", $item->parentId, \PDO::PARAM_INT); 696 $sth->bindValue(":linkedPage", $linkedPageId, \PDO::PARAM_INT); 697 $sth->bindValue(":title", $item->title, \PDO::PARAM_STR); 698 $sth->bindValue(":dateOnline", 699 $item->dateOnline->format("Y-m-d H:i:s"), \PDO::PARAM_STR); 700 $sth->bindValue(":dateOffline", $item->dateOffline 701 ? $item->dateOffline->format("Y-m-d H:i:s") 702 : null, \PDO::PARAM_STR); 703 704 $sth->execute(); 705 706 foreach ($item->properties as $prp) { 707 $this->updateProperty($prp, $item->id); 708 } 709 710 } 711 712 /** 713 * Create a new list item to insert in the database. 714 * 715 * @param \Scrivo\String $phpSelector The selector of the list item 716 * definition of the list item to create. 717 * 718 * @return \Scrivo\ListItem 719 */ 720 public function newItem(\Scrivo\String $phpSelector) { 721 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array(null)); 722 try { 723 $defId = $this->getDefinitionId($phpSelector); 724 725 return new \Scrivo\ListItem( 726 array( 727 "list_item_id" => 0, 728 "item_list_id" => $this->id, 729 "page_id" => $this->pageId, 730 "version" => 0, 731 "parent_id" => 0, 732 "sequence_no" => 0, 733 "list_item_definition_id" => $defId, 734 "link_id" => 0, 735 "title" => new \Scrivo\String(""), 736 "date_created" => "now", 737 "date_modified" => "now", 738 "date_online" => "now", 739 "date_offline" => null 740 ), 741 self::selectEmptyProperties($defId) 742 ); 743 744 } catch(\PDOException $e) { 745 throw new \Scrivo\ResourceException($e); 746 } 747 } 748 749 /** 750 * Save list item data to the database. 751 * 752 * @param \Scrivo\ListItem $item The list item to save, either an existing 753 * item updated item or a new one craeted with the newItem method. 754 * 755 * @throws \Scrivo\ApplicationException if the data is not accessible or 756 * it is not possible to insert or update the list item data. 757 */ 758 public function saveItem(\Scrivo\ListItem $item) { 759 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array(null)); 760 try { 761 $this->context->checkPermission( 762 \Scrivo\AccessController::WRITE_ACCESS, $this->pageId); 763 764 if ($item->id === 0) { 765 $this->insertItem($item); 766 } else { 767 $this->updateItem($item); 768 } 769 770 $this->removeFromCache(); 771 772 } catch(\PDOException $e) { 773 throw new \Scrivo\ResourceException($e); 774 } 775 } 776 777 /** 778 * Delete existing list item data from the database. 779 * 780 * First it is is checked if it's possible to delete list item data, 781 * then the list item data including its dependencies is deleted from 782 * the database. 783 * 784 * @param int $id The object id of the list item to delete. 785 * 786 * @throws \Scrivo\ApplicationException If the data is not accessible or 787 * if it is not possible to delete the list item data. 788 */ 789 public function deleteItem($id) { 790 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 791 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 792 )); 793 try { 794 // TODO test delete when there are children 795 $this->context->checkPermission( 796 \Scrivo\AccessController::WRITE_ACCESS, $this->pageId); 797 798 // TODO: delete sub page 799 800 $sth = $this->context->connection->prepare( 801 "DELETE FROM list_item 802 WHERE instance_id = :instId AND list_item_id = :id"); 803 804 $this->context->connection->bindInstance($sth); 805 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 806 807 $sth->execute(); 808 809 $sth = $this->context->connection->prepare( 810 "DELETE FROM list_item_property 811 WHERE instance_id = :instId AND list_item_id = :id"); 812 813 $this->context->connection->bindInstance($sth); 814 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 815 816 $sth->execute(); 817 818 $this->removeFromCache(); 819 820 } catch(\PDOException $e) { 821 throw new \Scrivo\ResourceException($e); 822 } 823 } 824 825 /** 826 * Move a list item to another position amongst its siblings. 827 * 828 * @param int $id The object id of the list item to move. 829 * @param int $dir Position or direction of the move, 830 * see \Scrivo\SequenceNo:::MOVE_* 831 */ 832 public function moveItem($id, $dir=\Scrivo\SequenceNo::MOVE_DOWN) { 833 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 834 array(\Scrivo\ArgumentCheck::TYPE_INTEGER), 835 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 836 )); 837 838 $this->context->checkPermission( 839 \Scrivo\AccessController::WRITE_ACCESS, $this->pageId); 840 841 \Scrivo\SequenceNo::position($this->context, "list_item", 842 array("parent_id", "item_list_id"), $id, $dir); 843 844 $this->removeFromCache(); 845 } 846 847 /** 848 * Remove this list (including all sub lists from the cache). 849 */ 850 private function removeFromCache() { 851 852 $cId = $this->pageId . "." . $this->pagePropertyDefinitionId; 853 if ($this->listPids) { 854 $listIds = array_keys($this->listPids); 855 foreach ($listIds as $id) { 856 unset($this->context->cache[$cId . "." . $id]); 857 } 858 } 859 unset($this->context->cache[$cId]); 860 } 861 862 863 } 864 865 ?>
Documentation generated by phpDocumentor 2.0.0a12 and ScrivoDocumentor on August 29, 2013