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       if ($this->getCompoundType() == "Document-PDF") {
00419          $qa = array(
00420             'CISOROOT' => $this->getCollection()->getAlias(),
00421             'CISOPTR' => ($this->isChild())
00422                ? $this->getParent()->getPtr() : $this->getPtr(),
00423             'CISOPAGE' => $this->getPage()
00424          );
00425          $base_uri = rtrim(DMHTTPRequest::getCurrent()->getURI()->getAbsoluteHostURI(), "/")
00426             . $this->config->getString("contentdm.showpdf_exe.path");
00427          return new DMURI(
00428             rtrim($base_uri, "/") . "?" . urldecode(http_build_query($qa)));
00429       }
00430       return DMInternalURI::getURIWithParams("api/1/objects"
00431          . $this->getCollection()->getAlias() . "/" . $this->getPtr()
00432          . "/bitstream");
00433    }
00434 
00445    public function getFullText() {
00446       /* Check for the presence of a non-empty "full" field. The object itself
00447       may have one; or, it may be a compound object, one or more of whose
00448       children would have one. We need to check both cases. */
00449       $text = $this->getMetadata("full");
00450       // Does the object itself have a non-empty fulltext field?
00451       if (!$text instanceof DMDCElement || strlen($text->getValue()) < 1) {
00452          // no, so check children, if applicable
00453          if ($this->hasChildren()) {
00454             $text = $this->getChild(0)->getMetadata("full");
00455          }
00456       }
00457       return $text;
00458    }
00459 
00464    public function getHeight() {
00465       return $this->getImageHeight();
00466    }
00467 
00479    public function getImageURL($maxwidth, $maxheight, $x = 0, $y = 0,
00480          $rotate = 0) {
00481       // check width & height
00482       // cdm defaults to 500 for each, cropped from x & y, not scaled.
00483       if ($maxwidth <= 0) $maxwidth = 500;
00484       if ($maxheight <= 0) $maxheight = 500;
00485 
00486       // check x & y
00487       if ($x <= 0) $x = 0;
00488       if ($y <= 0) $y = 0;
00489 
00490       // check rotation
00491       if ($rotate <= -360 || $rotate >= 360) $rotate = null;
00492 
00493       // calculate display scale
00494       $h = $this->getImageHeight();
00495       $w = $this->getImageWidth();
00496       if (!$h || !$w) {
00497          return false;
00498       }
00499       $hscale = ($maxheight / $h) * 100;
00500       $wscale = ($maxwidth / $w) * 100;
00501       $scale = ($hscale < $wscale) ? $hscale : $wscale;
00502 
00503       // set up query array for http_build_query()
00504       $qs = array(
00505          'CISOROOT' => $this->getCollection()->getAlias(),
00506          'CISOPTR' => $this->getPtr(),
00507          'DMSCALE' => round($scale, 6),
00508          'DMWIDTH' => $maxwidth,
00509          'DMHEIGHT' => $maxheight,
00510          'DMX' => $x,
00511          'DMY' => $y,
00512          'DMROTATE' => $rotate
00513       );
00514 
00515       return new DMURI(rtrim(DMHTTPRequest::getCurrent()->getURI()->getAbsoluteHostURI(), "/")
00516          . $this->config->getString("contentdm.getimage_exe.path")
00517          . "?" . urldecode(http_build_query($qs)));
00518    }
00519 
00524    public function getImageHeight() {
00525       if ($this->image_height < 1) {
00526          $this->instantiateFileProperties();
00527       }
00528       return $this->image_height;
00529    }
00530 
00535    public function getImageWidth() {
00536       if ($this->image_width < 1) {
00537          $this->instantiateFileProperties();
00538       }
00539       return $this->image_width;
00540    }
00541 
00550    public function getMetadata($nick = null) {
00551       if (count($this->metadata) < 1) {
00552          $this->instantiateFields();
00553       }
00554       if (!is_null($nick)) {
00555          foreach ($this->metadata as $field) {
00556             if ($field->getNick() == $nick) {
00557                return $field;
00558             }
00559          }
00560          return null;
00561       }
00562       return $this->metadata;
00563    }
00564 
00574    public function getMediaType() {
00575       $default_type = new DMMediaType("unknown", "unknown");
00576 
00577       // extract filename extension
00578       $tmp = explode(".", $this->getFilename());
00579       if (count($tmp) < 2) {
00580          // no extension, abort
00581          return $default_type;
00582       }
00583 
00584       // If the object is compound, it will have an extension of ".cpd,"
00585       // which isn't very useful. So use the extension of its first child
00586       // instead.
00587       if ($this->isCompound()) {
00588          return $this->getChild(0)->getMediaType();
00589       }
00590 
00591       $ext = strtolower($tmp[count($tmp)-1]);
00592       if ($ext == "cpd") {
00593          if ($this->getCompoundType() == "Document-PDF") {
00594             $ext = "pdf";
00595          }
00596       }
00597 
00598       $type = DMMediaType::getTypeForExtension($ext);
00599       if ($type) {
00600          return $type;
00601       }
00602       return $default_type;
00603    }
00604 
00608    public function getPage() {
00609       if ($this->page > 0) {
00610          return $this->page;
00611       }
00612       $this->setChildProperties();
00613       return $this->page;
00614    }
00615 
00619    public function getParent() {
00620       if ($this->parent_obj instanceof DMObject) {
00621          return $this->parent_obj;
00622       }
00623       dmGetCollectionParameters($this->getCollection()->getAlias(), $name,
00624             $path);
00625       $result = GetParent($this->getCollection()->getAlias(), $this->getPtr(),
00626             $path);
00627       if ($result > -1) {
00628          $this->parent_obj = DMObjectFactory::getObject(
00629             $this->getCollection(), $result);
00630          return $this->parent_obj;
00631       }
00632       return null;
00633    }
00634 
00638    public function getPtr() {
00639       return $this->ptr;
00640    }
00641 
00649    public function addRating(DMRating $r) {
00650       $this->data_store->addObjectRating($this, $r);
00651    }
00652 
00661    public function getRating($out_of = 100, $decimal_places = 10) {
00662       if ($out_of <> round($out_of) || $out_of < 1) {
00663          return false;
00664       }
00665       $rating = $this->data_store->getRatingForObject($this);
00666       $rating = ($rating / 100) * $out_of;
00667       return (float) round($rating, $decimal_places);
00668    }
00669 
00677    public function getReferenceURL() {
00678       return rtrim(DMHTTPRequest::getCurrent()->getURI()->getAbsoluteHostURI(), '/') . '/u?'
00679          . $this->getCollection()->getAlias() . ',' . $this->getPtr();
00680    }
00681 
00690    public function addTag(DMTag $tag) {
00691       $this->data_store->addObjectTag($this, $tag);
00692    }
00693 
00702    public function getThumbnail() {
00703       if (!$this->thumbnail_file) {
00704          // Temporary hack to work with dmulator's /dynamic collection.
00705          // Hope nobody has a collection called /dynamic...
00706          if ($this->getCollection()->getAlias() == "/dynamic") {
00707             $this->thumbnail_file = new DMFile(realpath(
00708                $this->config->getString("contentdm.collections.pathname")
00709                . $this->getCollection()->getAlias() . "/dynamic_thumb.jpg"));
00710          } else {
00711             $this->thumbnail_file = new DMFile(realpath(
00712                $this->config->getString("contentdm.collections.pathname")
00713                . $this->getCollection()->getAlias() . "/image/icon"
00714                . $this->getFile()->getNameWithoutExtension() . ".jpg"));
00715          }
00716       }
00717       return $this->thumbnail_file;
00718    }
00719 
00726    public function getThumbURL() {
00727       return $this->getThumbnailURL();
00728    }
00729 
00735    public function getThumbnailURL() {
00736       $qs = array(
00737          'CISOROOT' => $this->getCollection()->getAlias(),
00738          'CISOPTR' => $this->getPtr()
00739       );
00740       return new DMURI(rtrim(DMHTTPRequest::getCurrent()->getURI()->getAbsoluteHostURI(), "/")
00741          . $this->config->getString("contentdm.thumbnail_exe.path")
00742          . "?" . urldecode(http_build_query($qs)));
00743    }
00744 
00752    public function getTitle() {
00753       if (strlen($this->title) > 0) {
00754          return $this->title;
00755       }
00756       $this->setChildProperties();
00757       return $this->title;
00758    }
00759 
00760 
00775    public function getURI($component = DMBridgeComponent::TemplateEngine,
00776          $representation = null,
00777          $resolve_links = true) {
00778       if ($resolve_links) {
00779          // if it's a ".url" object, it will link elsewhere
00780          if ($this->isURLType()) {
00781             return $this->getFileURL();
00782          }
00783       }
00784       if ($component == DMBridgeComponent::TemplateEngine
00785             && $representation == null) {
00786          $representation = "html";
00787       } else if ($component == DMBridgeComponent::HTTPAPI
00788             && $representation == null) {
00789          $representation = DMHTTPRequest::getCurrent()->getUri()->getExtension();
00790       }
00791       return DMInternalURI::getResourceURI(
00792             $component,
00793             "objects" . $this->getCollection()->getAlias()
00794                . "/" . $this->getPtr(),
00795             $representation);
00796    }
00797 
00801    public function isURLType() {
00802       $tmp = explode(".", $this->getFilename());
00803       return (count($tmp) && $tmp[count($tmp) - 1] == "url");
00804    }
00805 
00814    public function getViewer($width_override = null, $height_override = null) {
00815       if (!$this->viewer) {
00816          $def = $this->getCollection()->getViewerDefinitionForMediaType(
00817                $this->getMediaType());
00818          if (!$def) {
00819             $def = $this->getCollection()->getViewerDefinitionForMediaType(
00820                   new DMMediaType("unknown", "unknown"));
00821          }
00822          if (!$def) {
00823             return null;
00824          }
00825          $width = ($width_override) ? $width_override : $def->getWidth();
00826          $height = ($height_override) ? $height_override : $def->getHeight();
00827          $mime = $def->getMediaType();
00828 
00829          try {
00830             $file = $this->getFile();
00831             if ((!$file && $this->hasChildren()) || $file->getMediaType()->equals(
00832                   new DMMediaType("application", "vnd.dmbridge.compound-object+xml"))) {
00833                $file = $this->getChild(0)->getFile();
00834             }
00835             
00836             $class = $def->getClass();
00837             if (!class_exists($class)) {
00838                throw new DMClassNotFoundException($class);
00839             }
00840             $this->viewer = new $class();
00841 
00842             if (!$this->viewer->isLowBandwidthCompatible()
00843                   && $file->getSize() > $def->getMaxFileSize()
00844                   && $def->getMaxFileSize() > 0) {
00845                $this->viewer = new DMFileLinkViewer();
00846             }
00847          } catch (DMFileNotFoundException $e) {
00848             $this->viewer = new DMNullViewer($this, $mime, $width, $height);
00849             $this->viewer->setMessage($e->getMessage());
00850          }
00851 
00852          // compound object PDFs will work only with this viewer.
00853          if ($this->getCompoundType() == "Document-PDF") {
00854             $this->viewer = new DMGenericPDFViewer();
00855          }
00856 
00857          $this->viewer->setObject($this);
00858          $this->viewer->setMediaType($mime);
00859          $this->viewer->setWidth($width);
00860          $this->viewer->setHeight($height);
00861       }
00862       return $this->viewer;
00863    }
00864 
00868    public function getViewerClassName() {
00869       $def = $this->getCollection()->getViewerDefinitionForMediaType(
00870             $this->getMediaType());
00871       if (!$def) {
00872          $def = $this->getCollection()->getViewerDefinitionForMediaType(
00873                new DMMediaType("unknown", "unknown"));
00874       }
00875       if (!$def) {
00876          return null;
00877       }
00878       return $def->getClass();
00879    }
00880 
00885    public function getWidth() {
00886       return $this->getImageWidth();
00887    }
00888 
00892    private function getCdmDOMDocument() {
00893       if ($this->cdm_domdocument) {
00894          return $this->cdm_domdocument;
00895       }
00896       $xml = null;
00897       dmGetItemInfo($this->getCollection()->getAlias(), $this->getPtr(), $xml);
00898       if (!empty($xml)) {
00899          $this->cdm_domdocument = new DOMDocument("1.0", "utf-8");
00900          /* dmGetItemInfo() may return non-UTF-8 character data, or
00901           * apparently even non-any-character-set data, which loadXML()
00902           * will, understandably, not deal with in a friendly way. If it's
00903           * invalid UTF-8, we run DMString::clean() on it which may either
00904           * strip out invalid characters, or strip out non-ASCII characters,
00905           * depending on the PHP version. We shouldn't have to do that.
00906           * Bug report filed w/ OCLC Support 2010-03-04 by adolski,
00907           * SR#1-642143637.
00908           */
00909          if (!DMString::isUTF8($xml)) {
00910             $xml = DMString::clean($xml);
00911          }
00912          $this->cdm_domdocument->loadXML($xml);
00913          return $this->cdm_domdocument;
00914       } else {
00915          throw new DMUnavailableModelException(
00916                DMLocalizedString::getString("NONEXISTENT_OBJECT"));
00917       }
00918    }
00919 
00923    private function getCompoundType() {
00924       if ($this->compound_type) {
00925          return $this->compound_type;
00926       }
00927       if ($this->isChild()) {
00928          $this->setChildProperties();
00929       }
00930 
00931       // get compound object structure
00932       dmGetCompoundObjectInfo(
00933          $this->getCollection()->getAlias(),
00934          $this->isChild() ? $this->getParent()->getPtr() : $this->getPtr(),
00935          $xml);
00936       if (!strlen($xml)) {
00937          return null;
00938       }
00939 
00940       $dxml = new DOMDocument("1.0", "utf-8");
00941       $dxml->loadXML($xml);
00942 
00943       $this->compound_type = $dxml->getElementsByTagName("type")->item(0)
00944             ->nodeValue;
00945       return $this->compound_type;
00946    }
00947 
00951    private function instantiateFields() {
00952       $dxml = $this->getCdmDOMDocument();
00953       // create DMDCElement objects from XML structure
00954       $skip_fields = array('find', 'dmaccess', 'dmcreated', 'dmmodified',
00955          'dmoclcno', 'dmrecord');
00956       $children = $dxml->documentElement->childNodes;
00957       if (!$children instanceof DOMNodeList) {
00958          return;
00959       }
00960       foreach ($children as $node) {
00961          if (in_array($node->nodeName, $skip_fields)) {
00962             continue;
00963          }
00964          $f = $this->getCollection()->getField($node->nodeName);
00965          if ($f instanceof DMDCElement) {
00966             $m = clone $f;
00967             $m->setValue((string) $node->nodeValue);
00968             $this->metadata[] = $m;
00969             unset($m, $f);
00970          }
00971       }
00972    }
00973 
00977    private function instantiateFileProperties() {
00978       $filename = $type = $width = $height = null;
00979       dmGetImageInfo($this->getCollection()->getAlias(),
00980          $this->getPtr(), $filename, $type, $width, $height);
00981       $this->setFilename($filename);
00982       $this->image_height = abs($height);
00983       $this->image_width = abs($width);
00984    }
00985 
00990    private function setChildProperties() {
00991       $xml = "";
00992       dmGetCollectionParameters($this->getCollection()->getAlias(), $name,
00993             $path);
00994       $result = GetParent($this->getCollection()->getAlias(),
00995             $this->getPtr(), $path);
00996       dmGetCompoundObjectInfo($this->getCollection()->getAlias(), $result,
00997             $xml);
00998       if (!$xml) {
00999          return;
01000       }
01001 
01002       // dmGetCompoundObjectInfo() may return invalid UTF-8;
01003       // see getCdmDOMDocument()
01004       if (!DMString::isUTF8($xml)) {
01005          $xml = DMString::clean($xml);
01006       }
01007       $dxml = new DOMDocument('1.0', 'utf-8');
01008       $dxml->loadXML($xml);
01009       $page = 1;
01010       $this->compound_type = $dxml->documentElement
01011             ->getElementsByTagName('type')->item(0)->nodeValue;
01012       foreach ($dxml->documentElement->getElementsByTagName('page') as $p) {
01013          if ($p->getElementsByTagName('pageptr')->item(0)->nodeValue
01014                == $this->getPtr()) {
01015             $this->page = (int) $page;
01016             $this->title = $p->getElementsByTagName('pagetitle')->item(0)
01017                   ->nodeValue;
01018             break;
01019          }
01020          $page++;
01021       }
01022    }
01023 
01024 }
 All Data Structures Functions Variables