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_FILEself::TYPE_FOLDER))
243          ));
244          $this->type $type;
245      }
246  
247      /**
248       * Set The asset title (&lt;title&gt;).
249       *
250       * @param \Scrivo\String $title The asset title (&lt;title&gt;).
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