dmBridge PHP API
DMObject.php
00001 <?php
00002 #
00003 # dmBridge: a data access framework for CONTENTdm(R)
00004 #
00005 # Copyright © 2009, 2010, 2011 Board of Regents of the Nevada System of Higher
00006 # Education, on behalf of the University of Nevada, Las Vegas
00007 #
00008 
00017 class DMObject extends DMModel implements DMURIAddressable {
00018 
00020    private $cdm_domdocument;
00023    private $children = array();
00025    private $collection;
00028    private $compound_type;
00030    private $config;
00032    private $data_store;
00034    private $date_created;
00036    private $date_updated;
00038    private $file;
00040    private $filename;
00042    private $image_height;
00044    private $image_width;
00046    private $metadata = array();
00048    private $page;
00050    private $parent_obj;
00052    private $ptr;
00054    private $thumbnail_file;
00056    private $title;
00058    private $viewer;
00059 
00065    public static function exists(DMCollection $col, $ptr) {
00066       $xml = null;
00067       dmGetItemInfo($col->getAlias(), $ptr, $xml);
00068       return (bool) $xml;
00069    }
00070 
00080    public function __construct(DMCollection $collection, $ptr,
00081          DMDataStore $data_store, DMConfigIni $config) {
00082       $this->collection = $collection;
00083       $this->ptr = abs($ptr);
00084       $this->data_store = $data_store;
00085       $this->config = $config;
00086    }
00087 
00093    public function __toString() {
00094       try {
00095          $value = ($this->getMetadata("title") instanceof DMDCElement)
00096             ? $this->getMetadata("title")->getValue()
00097             : $this->getCollection()->getAlias() . " " . $this->getPtr();
00098          return $value;
00099       } catch (Exception $e) {
00100          return $this->getCollection()->getAlias() . " " . $this->getPtr();
00101       }
00102    }
00103 
00112    public function getCdmURI() {
00113       $uri = clone DMHTTPRequest::getCurrent()->getURI()->getAbsoluteHostURI();
00114       if ($this->isCompound()) {
00115          $uri->setPath("/cdm4/document.php");
00116          $uri->addQueryValue("CISOROOT", $this->getCollection()->getAlias());
00117          $uri->addQueryValue("CISOPTR", $this->getPtr());
00118       } else if ($this->isChild()) {
00119          $uri->setPath("/cdm4/document.php");
00120          $uri->addQueryValue("CISOROOT", $this->getCollection()->getAlias());
00121          $uri->addQueryValue("CISOPTR", $this->getParent()->getPtr());
00122          $uri->addQueryValue("CISOSHOW", $this->getPtr());
00123       } else {
00124          $uri->setPath("/cdm4/item_viewer.php");
00125          $uri->addQueryValue("CISOROOT", $this->getCollection()->getAlias());
00126          $uri->addQueryValue("CISOPTR", $this->getPtr());
00127       }
00128       return $uri;
00129    }
00130 
00139    public function getChild($index) {
00140       $children = $this->getChildren();
00141       if (!array_key_exists($index, $children)) {
00142          return null;
00143       }
00144       return $children[$index];
00145    }
00146 
00150    public function isChild() {
00151       return ($this->getParent() instanceof DMObject);
00152    }
00153 
00160    public function getChildren() {
00161       if (count($this->children)) {
00162          return $this->children;
00163       }
00164 
00165       // get compound object structure
00166       $xml = null;
00167       dmGetCompoundObjectInfo(
00168          $this->getCollection()->getAlias(), $this->getPtr(), $xml);
00169       if (!strlen($xml)) {
00170          return array();
00171       }
00172 
00173       $dxml = new DOMDocument("1.0", "utf-8");
00174       $dxml->loadXML($xml);
00175 
00176       // instantiate children
00177       foreach ($dxml->getElementsByTagName("pageptr") as $page) {
00178          $this->children[] = DMObjectFactory::getObject(
00179             $this->getCollection(), (int) $page->nodeValue);
00180       }
00181       return $this->children;
00182    }
00183 
00191    public function hasChildren() {
00192       return (bool) count($this->getChildren());
00193    }
00194 
00198    public function getCollection() {
00199       return $this->collection;
00200    }
00201 
00210    public function addComment(DMComment $comment) {
00211       return $this->data_store->addObjectComment($this, $comment);
00212    }
00213 
00218    public function hasComments() {
00219       return (count($this->data_store
00220             ->getApprovedCommentsForObject($this, 1, 1000)) > 0);
00221    }
00222 
00229    public function getCommentsFeedURL() {
00230       $params = "objects" . $this->getCollection()->getAlias()
00231          . "/" . $this->getPtr() . "/comments";
00232       return DMInternalURI::getURIWithParams($params, array(), "atom");
00233    }
00234 
00240    public function isCompound() {
00241       if (count($this->children)) {
00242          return true;
00243       }
00244 
00245       // get compound object structure
00246       $xml = "";
00247       dmGetCompoundObjectInfo(
00248          $this->getCollection()->getAlias(), $this->getPtr(), $xml);
00249       return (bool) strlen($xml);
00250    }
00251 
00257    public function getDateCreated() {
00258       if (!$this->date_created instanceof DMDateTime) {
00259          $dxml = $this->getCdmDOMDocument();
00260          $created = $dxml->getElementsByTagName("dmcreated")->item(0)->nodeValue;
00261          $this->date_created = new DMDateTime($created);
00262       }
00263       return $this->date_created;
00264    }
00265 
00271    public function getDateUpdated() {
00272       if (!$this->date_updated instanceof DMDateTime) {
00273          $dxml = $this->getCdmDOMDocument();
00274          $updated = $dxml->getElementsByTagName('dmmodified')->item(0)->nodeValue;
00275          $this->setDateUpdated(new DMDateTime($updated));
00276       }
00277       return $this->date_updated;
00278    }
00279 
00283    protected function setDateUpdated(DMDateTime $date) {
00284       $this->date_updated = $date;
00285    }
00286 
00293    public function equals($obj) {
00294       return (is_object($obj) && $obj instanceof DMObject
00295             && $this->getCollection()->getAlias()
00296             == $obj->getCollection()->getAlias()
00297             && $this->getPtr() == $obj->getPtr());
00298    }
00299 
00306    public function isFavorite() {
00307       $session = DMHTTPRequest::getCurrent()->getSession();
00308       foreach ($session->getAllFavorites() as $f) {
00309          if ((string) $f == (string) $this) {
00310             return true;
00311          }
00312       }
00313       return false;
00314    }
00315 
00322    public function getFeedURI() {
00323       return $this->getURI(DMBridgeComponent::TemplateEngine, "atom");
00324    }
00325 
00332    public function getField($nick) {
00333       return $this->getMetadata($nick);
00334    }
00335 
00342    public function addField(DMDCElement $elem) {
00343       $count = count($this->metadata);
00344       for ($i = 0; $i < $count; $i++) {
00345          if ($this->metadata[$i]->getNick() == $elem->getNick()) {
00346             $this->metadata[$i] = $elem;
00347             return;
00348          }
00349       }
00350       $this->metadata[] = $elem;
00351    }
00352 
00360    public function getFields() {
00361       return $this->getMetadata();
00362    }
00363 
00374    public function getFile() {
00375       if (!$this->file) {
00376          $arg = $this->config->getString("contentdm.collections.pathname")
00377             . $this->getCollection()->getAlias() . "/image/"
00378             . $this->getFilename();
00379          switch ((string) $this->getMediaType()) {
00380             case "application/pdf":
00381                $this->file = new DMPDFFile($arg);
00382                break;
00383             default:
00384                $this->file = new DMFile($arg);
00385                break;
00386          }
00387       }
00388       return $this->file;
00389    }
00390 
00397    public function getFilename() {
00398       if (strlen($this->filename) < 1) {
00399          $this->instantiateFileProperties();
00400       }
00401       return basename($this->filename);
00402    }
00403 
00408    protected function setFilename($filename) {
00409       $this->filename = $filename;
00410    }
00411 
00417    public function getFileURL() {
00418       return DMInternalURI::getURIWithParams("api/1/objects"
00419             . $this->getCollection()->getAlias() . "/" . $this->getPtr()
00420             . "/bitstream");
00421    }
00422 
00433    public function getFullText() {
00434       /* Check for the presence of a non-empty "full" field. The object itself
00435       may have one; or, it may be a compound object, one or more of whose
00436       children would have one. We need to check both cases. */
00437       $text = $this->getMetadata("full");
00438       // Does the object itself have a non-empty fulltext field?
00439       if (!$text instanceof DMDCElement || strlen($text->getValue()) < 1) {
00440          // no, so check children, if applicable
00441          if ($this->hasChildren()) {
00442             $text = $this->getChild(0)->getMetadata("full");
00443          }
00444       }
00445       return $text;
00446    }
00447 
00452    public function getHeight() {
00453       return $this->getImageHeight();
00454    }
00455 
00467    public function getImageURL($maxwidth, $maxheight, $x = 0, $y = 0,
00468          $rotate = 0) {
00469       // check width & height
00470       // cdm defaults to 500 for each, cropped from x & y, not scaled.
00471       if ($maxwidth <= 0) $maxwidth = 500;
00472       if ($maxheight <= 0) $maxheight = 500;
00473 
00474       // check x & y
00475       if ($x <= 0) $x = 0;
00476       if ($y <= 0) $y = 0;
00477 
00478       // check rotation
00479       if ($rotate <= -360 || $rotate >= 360) $rotate = null;
00480 
00481       // calculate display scale
00482       $h = $this->getImageHeight();
00483       $w = $this->getImageWidth();
00484       if (!$h || !$w) {
00485          return false;
00486       }
00487       $hscale = ($maxheight / $h) * 100;
00488       $wscale = ($maxwidth / $w) * 100;
00489       $scale = ($hscale < $wscale) ? $hscale : $wscale;
00490 
00491       // set up query array for http_build_query()
00492       $qs = array(
00493          'CISOROOT' => $this->getCollection()->getAlias(),
00494          'CISOPTR' => $this->getPtr(),
00495          'DMSCALE' => round($scale, 6),
00496          'DMWIDTH' => $maxwidth,
00497          'DMHEIGHT' => $maxheight,
00498          'DMX' => $x,
00499          'DMY' => $y,
00500          'DMROTATE' => $rotate
00501       );
00502 
00503       return new DMURI(rtrim(DMHTTPRequest::getCurrent()->getURI()->getAbsoluteHostURI(), "/")
00504          . $this->config->getString("contentdm.getimage_exe.path")
00505          . "?" . urldecode(http_build_query($qs)));
00506    }
00507 
00512    public function getImageHeight() {
00513       if ($this->image_height < 1) {
00514          $this->instantiateFileProperties();
00515       }
00516       return $this->image_height;
00517    }
00518 
00523    public function getImageWidth() {
00524       if ($this->image_width < 1) {
00525          $this->instantiateFileProperties();
00526       }
00527       return $this->image_width;
00528    }
00529 
00538    public function getMetadata($nick = null) {
00539       if (count($this->metadata) < 1) {
00540          $this->instantiateFields();
00541       }
00542       if (!is_null($nick)) {
00543          foreach ($this->metadata as $field) {
00544             if ($field->getNick() == $nick) {
00545                return $field;
00546             }
00547          }
00548          return null;
00549       }
00550       return $this->metadata;
00551    }
00552 
00562    public function getMediaType() {
00563       $default_type = new DMMediaType("unknown", "unknown");
00564 
00565       // extract filename extension
00566       $tmp = explode(".", $this->getFilename());
00567       if (count($tmp) < 2) {
00568          // no extension, abort
00569          return $default_type;
00570       }
00571 
00572       // If the object is compound, it will have an extension of ".cpd,"
00573       // which isn't very useful. So use the extension of its first child
00574       // instead.
00575       if ($this->isCompound()) {
00576          return $this->getChild(0)->getMediaType();
00577       }
00578 
00579       $ext = strtolower($tmp[count($tmp)-1]);
00580       if ($ext == "cpd") {
00581          if ($this->getCompoundType() == "Document-PDF") {
00582             $ext = "pdf";
00583          }
00584       }
00585 
00586       $type = DMMediaType::getTypeForExtension($ext);
00587       if ($type) {
00588          return $type;
00589       }
00590       return $default_type;
00591    }
00592 
00596    public function getPage() {
00597       if ($this->page > 0) {
00598          return $this->page;
00599       }
00600       $this->setChildProperties();
00601       return $this->page;
00602    }
00603 
00607    public function getParent() {
00608       if ($this->parent_obj instanceof DMObject) {
00609          return $this->parent_obj;
00610       }
00611       dmGetCollectionParameters($this->getCollection()->getAlias(), $name,
00612             $path);
00613       $result = GetParent($this->getCollection()->getAlias(), $this->getPtr(),
00614             $path);
00615       if ($result > -1) {
00616          $this->parent_obj = DMObjectFactory::getObject(
00617             $this->getCollection(), $result);
00618          return $this->parent_obj;
00619       }
00620       return null;
00621    }
00622 
00626    public function getPtr() {
00627       return $this->ptr;
00628    }
00629 
00637    public function addRating(DMRating $r) {
00638       $this->data_store->addObjectRating($this, $r);
00639    }
00640 
00649    public function getRating($out_of = 100, $decimal_places = 10) {
00650       if ($out_of <> round($out_of) || $out_of < 1) {
00651          return false;
00652       }
00653       $rating = $this->data_store->getRatingForObject($this);
00654       $rating = ($rating / 100) * $out_of;
00655       return (float) round($rating, $decimal_places);
00656    }
00657 
00665    public function getReferenceURL() {
00666       return rtrim(DMHTTPRequest::getCurrent()->getURI()->getAbsoluteHostURI(), '/') . '/u?'
00667          . $this->getCollection()->getAlias() . ',' . $this->getPtr();
00668    }
00669 
00678    public function addTag(DMTag $tag) {
00679       $this->data_store->addObjectTag($this, $tag);
00680    }
00681 
00690    public function getThumbnail() {
00691       if (!$this->thumbnail_file) {
00692          // Temporary hack to work with dmulator's /dynamic collection.
00693          // Hope nobody has a collection called /dynamic...
00694          if ($this->getCollection()->getAlias() == "/dynamic") {
00695             $this->thumbnail_file = new DMFile(realpath(
00696                $this->config->getString("contentdm.collections.pathname")
00697                . $this->getCollection()->getAlias() . "/dynamic_thumb.jpg"));
00698          } else {
00699             $this->thumbnail_file = new DMFile(realpath(
00700                $this->config->getString("contentdm.collections.pathname")
00701                . $this->getCollection()->getAlias() . "/image/icon"
00702                . $this->getFile()->getNameWithoutExtension() . ".jpg"));
00703          }
00704       }
00705       return $this->thumbnail_file;
00706    }
00707 
00714    public function getThumbURL() {
00715       return $this->getThumbnailURL();
00716    }
00717 
00723    public function getThumbnailURL() {
00724       return DMInternalURI::getURIWithParams("api/1/objects"
00725          . $this->getCollection()->getAlias() . "/" . $this->getPtr()
00726          . "/thumbnail");
00727    }
00728 
00736    public function getTitle() {
00737       if (strlen($this->title) > 0) {
00738          return $this->title;
00739       }
00740       $this->setChildProperties();
00741       return $this->title;
00742    }
00743 
00744 
00759    public function getURI($component = DMBridgeComponent::TemplateEngine,
00760          $representation = null,
00761          $resolve_links = true) {
00762       if ($resolve_links) {
00763          // if it's a ".url" object, it will link elsewhere
00764          if ($this->isURLType()) {
00765             return $this->getFileURL();
00766          }
00767       }
00768       if ($component == DMBridgeComponent::TemplateEngine
00769             && $representation == null) {
00770          $representation = "html";
00771       } else if ($component == DMBridgeComponent::HTTPAPI
00772             && $representation == null) {
00773          $representation = DMHTTPRequest::getCurrent()->getUri()->getExtension();
00774       }
00775       return DMInternalURI::getResourceURI(
00776             $component,
00777             "objects" . $this->getCollection()->getAlias()
00778                . "/" . $this->getPtr(),
00779             $representation);
00780    }
00781 
00785    public function isURLType() {
00786       $tmp = explode(".", $this->getFilename());
00787       return (count($tmp) && $tmp[count($tmp) - 1] == "url");
00788    }
00789 
00798    public function getViewer($width_override = null, $height_override = null) {
00799       if (!$this->viewer) {
00800          $def = $this->getCollection()->getViewerDefinitionForMediaType(
00801                $this->getMediaType());
00802          if (!$def) {
00803             $def = $this->getCollection()->getViewerDefinitionForMediaType(
00804                   new DMMediaType("unknown", "unknown"));
00805          }
00806          if (!$def) {
00807             return null;
00808          }
00809          $width = ($width_override) ? $width_override : $def->getWidth();
00810          $height = ($height_override) ? $height_override : $def->getHeight();
00811          $mime = $def->getMediaType();
00812 
00813          try {
00814             $file = $this->getFile();
00815             if ((!$file && $this->hasChildren()) || $file->getMediaType()->equals(
00816                   new DMMediaType("application", "vnd.dmbridge.compound-object+xml"))) {
00817                $file = $this->getChild(0)->getFile();
00818             }
00819             $class = ($file->getSize() > $def->getMaxFileSize())
00820                ? "DMFileLinkViewer" : $def->getClass();
00821 
00822             if (!class_exists($class)) {
00823                throw new DMClassNotFoundException($class);
00824             }
00825             $this->viewer = new $class($this, $mime, $width, $height);
00826          } catch (DMFileNotFoundException $e) {
00827             $this->viewer = new DMNullViewer($this, $mime, $width, $height);
00828             $this->viewer->setMessage($e->getMessage());
00829          }
00830       }
00831       return $this->viewer;
00832    }
00833 
00837    public function getViewerClassName() {
00838       $def = $this->getCollection()->getViewerDefinitionForMediaType(
00839             $this->getMediaType());
00840       if (!$def) {
00841          $def = $this->getCollection()->getViewerDefinitionForMediaType(
00842                new DMMediaType("unknown", "unknown"));
00843       }
00844       if (!$def) {
00845          return null;
00846       }
00847       return $def->getClass();
00848    }
00849 
00854    public function getWidth() {
00855       return $this->getImageWidth();
00856    }
00857 
00861    private function getCdmDOMDocument() {
00862       if ($this->cdm_domdocument) {
00863          return $this->cdm_domdocument;
00864       }
00865       $xml = null;
00866       dmGetItemInfo($this->getCollection()->getAlias(), $this->getPtr(), $xml);
00867       if (!empty($xml)) {
00868          $this->cdm_domdocument = new DOMDocument("1.0", "utf-8");
00869          /* dmGetItemInfo() may return non-UTF-8 character data, or
00870           * apparently even non-any-character-set data, which loadXML()
00871           * will, understandably, not deal with in a friendly way. If it's
00872           * invalid UTF-8, we run DMString::clean() on it which may either
00873           * strip out invalid characters, or strip out non-ASCII characters,
00874           * depending on the PHP version. We shouldn't have to do that.
00875           * Bug report filed w/ OCLC Support 2010-03-04 by adolski,
00876           * SR#1-642143637.
00877           */
00878          if (!DMString::isUTF8($xml)) {
00879             $xml = DMString::clean($xml);
00880          }
00881          $this->cdm_domdocument->loadXML($xml);
00882          return $this->cdm_domdocument;
00883       } else {
00884          throw new DMUnavailableModelException(
00885                DMLocalizedString::getString("NONEXISTENT_OBJECT"));
00886       }
00887    }
00888 
00892    private function getCompoundType() {
00893       if ($this->compound_type) {
00894          return $this->compound_type;
00895       }
00896       if ($this->isChild()) {
00897          $this->setChildProperties();
00898       }
00899 
00900       // get compound object structure
00901       dmGetCompoundObjectInfo(
00902          $this->getCollection()->getAlias(),
00903          $this->isChild() ? $this->getParent()->getPtr() : $this->getPtr(),
00904          $xml);
00905       if (!strlen($xml)) {
00906          return null;
00907       }
00908 
00909       $dxml = new DOMDocument("1.0", "utf-8");
00910       $dxml->loadXML($xml);
00911 
00912       $this->compound_type = $dxml->getElementsByTagName("type")->item(0)
00913             ->nodeValue;
00914       return $this->compound_type;
00915    }
00916 
00920    private function instantiateFields() {
00921       $dxml = $this->getCdmDOMDocument();
00922       // create DMDCElement objects from XML structure
00923       $skip_fields = array('find', 'dmaccess', 'dmcreated', 'dmmodified',
00924          'dmoclcno', 'dmrecord');
00925       $children = $dxml->documentElement->childNodes;
00926       if (!$children instanceof DOMNodeList) {
00927          return;
00928       }
00929       foreach ($children as $node) {
00930          if (in_array($node->nodeName, $skip_fields)) {
00931             continue;
00932          }
00933          $f = $this->getCollection()->getField($node->nodeName);
00934          if ($f instanceof DMDCElement) {
00935             $m = clone $f;
00936             $m->setValue((string) $node->nodeValue);
00937             $this->metadata[] = $m;
00938             unset($m, $f);
00939          }
00940       }
00941    }
00942 
00946    private function instantiateFileProperties() {
00947       $filename = $type = $width = $height = null;
00948       dmGetImageInfo($this->getCollection()->getAlias(),
00949          $this->getPtr(), $filename, $type, $width, $height);
00950       $this->setFilename($filename);
00951       $this->image_height = abs($height);
00952       $this->image_width = abs($width);
00953    }
00954 
00959    private function setChildProperties() {
00960       $xml = "";
00961       dmGetCollectionParameters($this->getCollection()->getAlias(), $name,
00962             $path);
00963       $result = GetParent($this->getCollection()->getAlias(),
00964             $this->getPtr(), $path);
00965       dmGetCompoundObjectInfo($this->getCollection()->getAlias(), $result,
00966             $xml);
00967       if (!$xml) {
00968          return;
00969       }
00970 
00971       // dmGetCompoundObjectInfo() may return invalid UTF-8;
00972       // see getCdmDOMDocument()
00973       if (!DMString::isUTF8($xml)) {
00974          $xml = DMString::clean($xml);
00975       }
00976       $dxml = new DOMDocument('1.0', 'utf-8');
00977       $dxml->loadXML($xml);
00978       $page = 1;
00979       $this->compound_type = $dxml->documentElement
00980             ->getElementsByTagName('type')->item(0)->nodeValue;
00981       foreach ($dxml->documentElement->getElementsByTagName('page') as $p) {
00982          if ($p->getElementsByTagName('pageptr')->item(0)->nodeValue
00983                == $this->getPtr()) {
00984             $this->page = (int) $page;
00985             $this->title = $p->getElementsByTagName('pagetitle')->item(0)
00986                   ->nodeValue;
00987             break;
00988          }
00989          $page++;
00990       }
00991    }
00992 
00993 }
 All Data Structures Functions Variables