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: Asset.php 866 2013-08-25 16:22:35Z geert $ 30 */ 31 32 /** 33 * Implementation of the \Scrivo\Asset class. 34 */ 35 36 namespace Scrivo; 37 38 /** 39 */ 40 abstract class Asset { 41 42 /** 43 * Value indicating that the asset is a folder. 44 */ 45 const TYPE_FOLDER = 0; 46 47 /** 48 * Value indicating that the asset is a file. 49 */ 50 const TYPE_FILE = 1; 51 52 /** 53 * The asset id (DB key). 54 * @var int 55 */ 56 protected $id = 0; 57 58 /** 59 * The id of the parent asset. 60 * @var int 61 */ 62 protected $parentId = 0; 63 64 /** 65 * The asset type: one out of the Asset::TYPE_* constant values. 66 * @var int 67 */ 68 protected $type = 0; 69 70 /** 71 * The asset title. 72 * @var \Scrivo\String 73 */ 74 protected $title = null; 75 76 /** 77 * The date/time that this asset was created. 78 * @var \DateTime 79 */ 80 protected $dateCreated = null; 81 82 /** 83 * The last date/time that this asset was modified. 84 * @var \DateTime 85 */ 86 protected $dateModified = null; 87 88 /** 89 * The child assets of this asset. 90 * @var \Scrivo\AssetSet 91 */ 92 protected $children = null; 93 94 /** 95 * The parent assets of this asset. 96 * @var \Scrivo\AssetSet 97 */ 98 protected $path = null; 99 100 /** 101 * The attached roles. 102 * @var \Scrivo\RoleSet 103 */ 104 protected $roles = null; 105 106 /** 107 * A Scrivo context. 108 * @var \Scrivo\Context 109 */ 110 protected $context = null; 111 112 /** 113 * Create an empty asset object. 114 * 115 * @param \Scrivo\Context $context A Scrivo context. 116 */ 117 public function __construct(\Scrivo\Context $context=null) { 118 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array(null), 0); 119 120 if ($context) { 121 $this->id = 0; 122 $this->parentId = 0; 123 $this->type = 0; 124 $this->title = new \Scrivo\String(); 125 $this->dateCreated = new \DateTime("now"); 126 $this->dateModified = new \DateTime("now"); 127 128 $this->roles = new \Scrivo\RoleSet(); 129 130 $this->context = $context; 131 } 132 } 133 134 /** 135 * Implementation of the readable properties using the PHP magic 136 * method __get(). 137 * 138 * @param string $name The name of the property to get. 139 * 140 * @return mixed The value of the requested property. 141 */ 142 public function __get($name) { 143 switch($name) { 144 case "id": return $this->id; 145 case "parentId": return $this->parentId; 146 case "type": return $this->type; 147 case "title": return $this->title; 148 case "dateCreated": return $this->dateCreated; 149 case "dateModified": return $this->dateModified; 150 case "children": return $this->getChildren(); 151 case "path": return $this->getPath(); 152 case "roles": return $this->roles; 153 case "context": return $this->context; 154 } 155 throw new \Scrivo\SystemException("No such property-get '$name'."); 156 } 157 158 /** 159 * Implementation of the writable properties using the PHP magic 160 * method __set(). 161 * 162 * @param string $name The name of the property to set. 163 * @param mixed $value The value of the property to set. 164 */ 165 public function __set($name, $value) { 166 switch($name) { 167 case "parentId": $this->setParentId($value); return; 168 case "type": $this->setType($value); return; 169 case "title": $this->setTitle($value); return; 170 case "context": $this->setContext($value); return; 171 } 172 throw new \Scrivo\SystemException("No such property-set '$name'."); 173 } 174 175 /** 176 * Convenience method to set the fields of a asset definition object from 177 * an array (result set row). 178 * 179 * @param \Scrivo\Context $context A Scrivo context. 180 * @param array $rd An array containing the field data using the database 181 * field names as keys. 182 */ 183 protected function setFields(\Scrivo\Context $context, array $rd) { 184 185 $this->id = intval($rd["asset_id"]); 186 $this->parentId = intval($rd["parent_id"]); 187 $this->type = intval($rd["type"]); 188 $this->title = new \Scrivo\String($rd["title"]); 189 $this->dateCreated = new \DateTime($rd["date_created"]); 190 $this->dateModified = new \DateTime($rd["date_modified"]); 191 192 $this->context = $context; 193 } 194 195 /** 196 * Get the child assets of this asset. 197 * 198 * @return \Scrivo\AssetSet The child assets of the asset. 199 */ 200 private function getChildren() { 201 if ($this->children === null) { 202 $this->children = self::selectChildren($this); 203 $this->context->cache[$this->id] = $this; 204 } 205 return $this->children; 206 } 207 208 /** 209 * Get the child assets of this asset. 210 * 211 * @return \Scrivo\AssetSet All assets above the current asset. 212 */ 213 private function getPath() { 214 if ($this->path === null) { 215 $this->path = self::selectPath($this); 216 $this->context->cache[$this->id] = $this; 217 } 218 return $this->path; 219 } 220 221 /** 222 * Set the id of the parent asset. 223 * 224 * @param int $parentId The id of the parent asset. 225 */ 226 private function setParentId($parentId) { 227 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 228 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 229 )); 230 $this->parentId = $parentId; 231 } 232 233 /** 234 * Set the asset type: one out of the Asset::TYPE_* constant values. 235 * 236 * @param int $type The asset type: one out of the Asset::TYPE_* constant 237 * values. 238 */ 239 private function setType($type) { 240 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 241 array(\Scrivo\ArgumentCheck::TYPE_INTEGER, array( 242 self::TYPE_FILE, self::TYPE_FOLDER)) 243 )); 244 $this->type = $type; 245 } 246 247 /** 248 * Set The asset title (<title>). 249 * 250 * @param \Scrivo\String $title The asset title (<title>). 251 */ 252 private function setTitle(\Scrivo\String $title) { 253 $this->title = $title; 254 } 255 256 /** 257 * Set the asset context. 258 * 259 * @param \Scrivo\Context $context A Scrivo context. 260 */ 261 private function setContext(\Scrivo\Context $context) { 262 $this->context = $context; 263 } 264 265 /** 266 * Select the roles for this asset. 267 * 268 * @param \Scrivo\Context $context A valid Scrivo context. 269 * @param array $assets the set of assets for which to retrieve the 270 * properties. 271 */ 272 private static function selectRoles(\Scrivo\Context $context, array $assets) { 273 274 $ids = implode(",", array_keys($assets)); 275 276 $sth = $context->connection->prepare( 277 "SELECT page_id, role_id FROM object_role 278 WHERE instance_id = :instId AND page_id in ($ids)"); 279 280 $context->connection->bindInstance($sth); 281 282 $sth->execute(); 283 284 while ($rd = $sth->fetch(\PDO::FETCH_ASSOC)) { 285 286 $assets[intval($rd["page_id"])]->roles[] = 287 intval($rd["role_id"]); 288 289 } 290 } 291 292 /** 293 * Move a asset one position up or down amongst its siblings. 294 * 295 * @param int $dir Direction of the move, see \Scrivo\SequenceNo:::MOVE_* 296 */ 297 function move($dir=\Scrivo\SequenceNo::MOVE_DOWN) { 298 299 $this->context->checkPermission( 300 \Scrivo\AccessController::WRITE_ACCESS, $this->id); 301 302 \Scrivo\SequenceNo::position($this->context, "asset", 303 "parent_id", $this->id, $dir); 304 305 unset($this->context->cache[$this->parentId]); 306 307 } 308 309 310 /** 311 * Delete an existing asset from the database. 312 * 313 * First it is is checked if it's possible to delete this asset 314 * then the asset data including its dependecies is deleted from 315 * the database. 316 * 317 * @param \Scrivo\Context $context A Scrivo context. 318 * @param int $id The id of the asset to delete. 319 * 320 * @throws \Scrivo\ApplicationException If it is not possible to delete 321 * this asset. 322 */ 323 public static function delete(\Scrivo\Context $context, $id) { 324 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 325 null, 326 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 327 )); 328 try { 329 static::validateDelete($context, $id); 330 331 $p = \Scrivo\Asset::fetch($context, $id); 332 333 foreach (array("object_role" => "page_id", 334 "id_label" => "id", 335 "asset" => "asset_id") as $table => $keyFld) { 336 337 $sth = $context->connection->prepare( 338 "DELETE FROM $table 339 WHERE instance_id = :instId AND $keyFld = :id"); 340 341 $context->connection->bindInstance($sth); 342 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 343 344 $sth->execute(); 345 } 346 347 unset($context->cache[$id]); 348 unset($context->cache[$p->parentId]); 349 350 } catch(\PDOException $e) { 351 throw new \Scrivo\ResourceException($e); 352 } 353 } 354 355 /** 356 * Retrieve a asset from the database or cache. 357 * 358 * @param \Scrivo\Context $context A Scrivo context. 359 * @param int $id An object id of a asset. 360 * 361 * @throws \Scrivo\ApplicationException if the asset was not readable for 362 * the user defined in the context. 363 */ 364 public static function fetch(\Scrivo\Context $context, $id=null) { 365 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 366 null, 367 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 368 ), 1); 369 try { 370 // Try to retieve form cache 371 $a = null; 372 if (isset($context->cache[$id])) { 373 // Set the asset from cache and set the context. 374 $a = $context->cache[$id]; 375 $a->context = $context; 376 } else { 377 378 $sth = $context->connection->prepare( 379 "SELECT asset_id, parent_id, type, size, 380 date_created, date_modified, date_online, date_offline, 381 title, location, mime_type 382 FROM asset 383 WHERE instance_id = :instId AND asset_id = :id"); 384 385 $context->connection->bindInstance($sth); 386 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 387 388 $sth->execute(); 389 390 if ($sth->rowCount() != 1) { 391 throw new \Scrivo\SystemException("Failed to load asset"); 392 } 393 394 $rd = $sth->fetch(\PDO::FETCH_ASSOC); 395 396 $a = intval($rd["type"]) ? 397 new \Scrivo\File() : new \Scrivo\Folder(); 398 $a->setFields($context, $rd); 399 400 $a->roles = new \Scrivo\RoleSet(); 401 self::selectRoles($a->context, array($a->type 402 ? $a->parentId : $a->id => $a)); 403 404 $context->cache[$id] = $a; 405 } 406 407 $a->roles->checkReadPermission($context->principal); 408 return $a; 409 410 } catch(\PDOException $e) { 411 throw new \Scrivo\ResourceException($e); 412 } 413 } 414 415 /** 416 * Select child assets from the database. 417 * 418 * @param \Scrivo\Asset $asset A Scrivo asset. 419 * 420 * @return \Scrivo\AssetSet An array containing the selected assets. 421 */ 422 private static function selectChildren(\Scrivo\Asset $asset) { 423 try { 424 $sth = $asset->context->connection->prepare( 425 "SELECT A.asset_id, A.parent_id, A.type, A.size, 426 A.date_created, A.date_modified, A.date_online, A.date_offline, 427 A.title, A.location, A.mime_type, R.role_id 428 FROM asset A LEFT JOIN object_role R ON 429 (A.instance_id = R.instance_id AND 430 IF(A.type=0, A.asset_id, A.parent_id) = R.page_id) 431 WHERE A.instance_id = :instId 432 AND A.parent_id = :parentId 433 ORDER BY sequence_no"); 434 435 $asset->context->connection->bindInstance($sth); 436 $sth->bindValue(":parentId", $asset->id, \PDO::PARAM_INT); 437 438 $sth->execute(); 439 $res = new \Scrivo\AssetSet($asset); 440 $a = null; 441 $lid = 0; 442 $id = 0; 443 444 while ($rd = $sth->fetch(\PDO::FETCH_ASSOC)) { 445 446 $id = intval($rd["asset_id"]); 447 448 if ($lid != $id) { 449 450 if ($lid !== 0) { 451 $asset->context->cache[$lid] = $a; 452 $res[$lid] = $a; 453 } 454 $lid = $id; 455 456 $a = intval($rd["type"]) ? 457 new \Scrivo\File() : new \Scrivo\Folder(); 458 $a->setFields($asset->context, $rd); 459 $a->roles = new \Scrivo\RoleSet(); 460 } 461 462 // Add the roles to the role set 463 $a->roles[] = intval($rd["role_id"]); 464 } 465 466 if ($id) { 467 $asset->context->cache[$id] = $a; 468 $res[$id] = $a; 469 } 470 471 return $res; 472 473 } catch(\PDOException $e) { 474 throw new \Scrivo\ResourceException($e); 475 } 476 } 477 478 /** 479 * Select the asset path. 480 * 481 * @param \Scrivo\Asset $asset A Scrivo asset. 482 * 483 * @return \Scrivo\AssetSet An array containing the selected assets. 484 */ 485 protected static function selectPath(\Scrivo\Asset $asset) { 486 try { 487 488 $res = new \Scrivo\AssetSet($asset); 489 $target = $asset->parentId; 490 491 $i = 0; 492 while ($target) { 493 494 if ($target == $asset->id) { 495 throw new \Scrivo\SystemException("Path loop"); 496 } 497 498 if (isset($asset->context->cache[$target])) { 499 500 $a = $asset->context->cache[$target]; 501 502 } else { 503 504 $sth = $asset->context->connection->prepare( 505 "SELECT A.asset_id, A.parent_id, A.type, A.size, 506 A.date_created, A.date_modified, A.date_online, A.date_offline, 507 A.title, A.location, A.mime_type, R.role_id 508 FROM asset A LEFT JOIN object_role R ON 509 (A.instance_id = R.instance_id AND 510 IF(A.type=0, A.asset_id, A.parent_id) = 511 R.page_id) 512 WHERE A.instance_id = :instId 513 AND A.asset_id = :parentId"); 514 515 $asset->context->connection->bindInstance($sth); 516 $sth->bindValue(":parentId", $target, \PDO::PARAM_INT); 517 518 $sth->execute(); 519 $a = null; 520 521 while ($rd = $sth->fetch(\PDO::FETCH_ASSOC)) { 522 523 if (!$a) { 524 $a = intval($rd["type"]) ? 525 new \Scrivo\File() : new \Scrivo\Folder(); 526 $a->setFields($asset->context, $rd); 527 $a->roles = new \Scrivo\RoleSet(); 528 $target = intval($rd["asset_id"]); 529 } 530 531 // Add the roles to the role set 532 $a->roles[] = intval($rd["role_id"]); 533 } 534 535 if ($a) { 536 $asset->context->cache[$a->id] = $a; 537 } else { 538 throw new \Scrivo\SystemException( 539 "Failed to load asset"); 540 } 541 542 } 543 544 $res->prepend($a); 545 546 $target = $a->parentId; 547 548 } 549 550 return $res; 551 552 } catch(\PDOException $e) { 553 throw new \Scrivo\ResourceException($e); 554 } 555 } 556 557 } 558 559 ?>
Documentation generated by phpDocumentor 2.0.0a12 and ScrivoDocumentor on August 29, 2013