1<?php 2 3/** 4 * EasyRdf 5 * 6 * LICENSE 7 * 8 * Copyright (c) 2009-2013 Nicholas J Humfrey. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or 18 * promote products derived from this software without specific prior 19 * written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 * @package EasyRdf 34 * @copyright Copyright (c) 2009-2013 Nicholas J Humfrey 35 * @license http://www.opensource.org/licenses/bsd-license.php 36 */ 37 38/** 39 * Class that represents an RDF resource 40 * 41 * @package EasyRdf 42 * @copyright Copyright (c) 2009-2013 Nicholas J Humfrey 43 * @license http://www.opensource.org/licenses/bsd-license.php 44 */ 45class EasyRdf_Resource 46{ 47 /** The URI for this resource */ 48 protected $uri = null; 49 50 /** The Graph that this resource belongs to */ 51 protected $graph = null; 52 53 54 /** Constructor 55 * 56 * * Please do not call new EasyRdf_Resource() directly * 57 * 58 * To create a new resource use the get method in a graph: 59 * $resource = $graph->resource('http://www.example.com/'); 60 * 61 */ 62 public function __construct($uri, $graph = null) 63 { 64 if (!is_string($uri) or $uri == null or $uri == '') { 65 throw new InvalidArgumentException( 66 "\$uri should be a string and cannot be null or empty" 67 ); 68 } 69 70 $this->uri = $uri; 71 72 # Check that $graph is an EasyRdf_Graph object 73 if (is_object($graph) and $graph instanceof EasyRdf_Graph) { 74 $this->graph = $graph; 75 } elseif (!is_null($graph)) { 76 throw new InvalidArgumentException( 77 "\$graph should be an EasyRdf_Graph object" 78 ); 79 } 80 } 81 82 /** 83 * Return the graph that this resource belongs to 84 * 85 * @return EasyRdf_Graph 86 */ 87 public function getGraph() 88 { 89 return $this->graph; 90 } 91 92 /** Returns the URI for the resource. 93 * 94 * @return string URI of this resource. 95 */ 96 public function getUri() 97 { 98 return $this->uri; 99 } 100 101 /** Check to see if a resource is a blank node. 102 * 103 * @return bool True if this resource is a blank node. 104 */ 105 public function isBNode() 106 { 107 if (substr($this->uri, 0, 2) == '_:') { 108 return true; 109 } else { 110 return false; 111 } 112 } 113 114 /** Get the identifier for a blank node 115 * 116 * Returns null if the resource is not a blank node. 117 * 118 * @return string The identifer for the bnode 119 */ 120 public function getBNodeId() 121 { 122 if (substr($this->uri, 0, 2) == '_:') { 123 return substr($this->uri, 2); 124 } else { 125 return null; 126 } 127 } 128 129 /** Get a the prefix of the namespace that this resource is part of 130 * 131 * This method will return null the resource isn't part of any 132 * registered namespace. 133 * 134 * @return string The namespace prefix of the resource (e.g. foaf) 135 */ 136 public function prefix() 137 { 138 return EasyRdf_Namespace::prefixOfUri($this->uri); 139 } 140 141 /** Get a shortened version of the resources URI. 142 * 143 * This method will return the full URI if the resource isn't part of any 144 * registered namespace. 145 * 146 * @return string The shortened URI of this resource (e.g. foaf:name) 147 */ 148 public function shorten() 149 { 150 return EasyRdf_Namespace::shorten($this->uri); 151 } 152 153 /** Gets the local name of the URI of this resource 154 * 155 * The local name is defined as the part of the URI string 156 * after the last occurrence of the '#', ':' or '/' character. 157 * 158 * @return string The local name 159 */ 160 public function localName() 161 { 162 if (preg_match("|([^#:/]+)$|", $this->uri, $matches)) { 163 return $matches[1]; 164 } 165 } 166 167 /** Parse the URI of the resource and return as a ParsedUri object 168 * 169 * @return EasyRdf_ParsedUri 170 */ 171 public function parseUri() 172 { 173 return new EasyRdf_ParsedUri($this->uri); 174 } 175 176 /** Generates an HTML anchor tag, linking to this resource. 177 * 178 * If no text is given, then the URI also uses as the link text. 179 * 180 * @param string $text Text for the link. 181 * @param array $options Associative array of attributes for the anchor tag 182 * @return string The HTML link string 183 */ 184 public function htmlLink($text = null, $options = array()) 185 { 186 $options = array_merge(array('href' => $this->uri), $options); 187 if ($text === null) { 188 $text = $this->uri; 189 } 190 191 $html = "<a"; 192 foreach ($options as $key => $value) { 193 if (!preg_match('/^[-\w]+$/', $key)) { 194 throw new InvalidArgumentException( 195 "\$options should use valid attribute names as keys" 196 ); 197 } 198 199 $html .= " ".htmlspecialchars($key)."=\"". 200 htmlspecialchars($value)."\""; 201 } 202 $html .= ">".htmlspecialchars($text)."</a>"; 203 204 return $html; 205 } 206 207 /** Returns the properties of the resource as an RDF/PHP associative array 208 * 209 * For example: 210 * array('type' => 'uri', 'value' => 'http://www.example.com/') 211 * 212 * @return array The properties of the resource 213 */ 214 public function toRdfPhp() 215 { 216 if ($this->isBNode()) { 217 return array('type' => 'bnode', 'value' => $this->uri); 218 } else { 219 return array('type' => 'uri', 'value' => $this->uri); 220 } 221 } 222 223 /** Return pretty-print view of the resource 224 * 225 * @param string $format Either 'html' or 'text' 226 * @param string $color The colour of the text 227 * @return string 228 */ 229 public function dumpValue($format = 'html', $color = 'blue') 230 { 231 return EasyRdf_Utils::dumpResourceValue($this, $format, $color); 232 } 233 234 /** Magic method to return URI of resource when casted to string 235 * 236 * @return string The URI of the resource 237 */ 238 public function __toString() 239 { 240 return $this->uri; 241 } 242 243 244 245 /** Throw can exception if the resource does not belong to a graph 246 * @ignore 247 */ 248 protected function checkHasGraph() 249 { 250 if (!$this->graph) { 251 throw new EasyRdf_Exception( 252 "EasyRdf_Resource is not part of a graph." 253 ); 254 } 255 } 256 257 /** Perform a load (download of remote URI) of the resource into the graph 258 * 259 * The document type is optional but should be specified if it 260 * can't be guessed or got from the HTTP headers. 261 * 262 * @param string $format Optional format of the data (eg. rdfxml) 263 */ 264 public function load($format = null) 265 { 266 $this->checkHasGraph(); 267 return $this->graph->load($this->uri, $format); 268 } 269 270 /** Delete a property (or optionally just a specific value) 271 * 272 * @param string $property The name of the property (e.g. foaf:name) 273 * @param object $value The value to delete (null to delete all values) 274 * @return null 275 */ 276 public function delete($property, $value = null) 277 { 278 $this->checkHasGraph(); 279 return $this->graph->delete($this->uri, $property, $value); 280 } 281 282 /** Add values to for a property of the resource 283 * 284 * Example: 285 * $resource->add('prefix:property', 'value'); 286 * 287 * @param mixed $property The property name 288 * @param mixed $value The value for the property 289 * @return integer The number of values added (1 or 0) 290 */ 291 public function add($property, $value) 292 { 293 $this->checkHasGraph(); 294 return $this->graph->add($this->uri, $property, $value); 295 } 296 297 /** Add a literal value as a property of the resource 298 * 299 * The value can either be a single value or an array of values. 300 * 301 * Example: 302 * $resource->add('dc:title', 'Title of Page'); 303 * 304 * @param mixed $property The property name 305 * @param mixed $values The value or values for the property 306 * @param string $lang The language of the literal 307 * @return integer The number of values added 308 */ 309 public function addLiteral($property, $values, $lang = null) 310 { 311 $this->checkHasGraph(); 312 return $this->graph->addLiteral($this->uri, $property, $values, $lang); 313 } 314 315 /** Add a resource as a property of the resource 316 * 317 * Example: 318 * $bob->add('foaf:knows', 'http://example.com/alice'); 319 * 320 * @param mixed $property The property name 321 * @param mixed $resource2 The resource to be the value of the property 322 * @return integer The number of values added (1 or 0) 323 */ 324 public function addResource($property, $resource2) 325 { 326 $this->checkHasGraph(); 327 return $this->graph->addResource($this->uri, $property, $resource2); 328 } 329 330 /** Set value for a property 331 * 332 * The new value(s) will replace the existing values for the property. 333 * The name of the property should be a string. 334 * If you set a property to null or an empty array, then the property 335 * will be deleted. 336 * 337 * @param string $property The name of the property (e.g. foaf:name) 338 * @param mixed $value The value for the property. 339 * @return integer The number of values added (1 or 0) 340 */ 341 public function set($property, $value) 342 { 343 $this->checkHasGraph(); 344 return $this->graph->set($this->uri, $property, $value); 345 } 346 347 /** Get a single value for a property 348 * 349 * If multiple values are set for a property then the value returned 350 * may be arbitrary. 351 * 352 * If $property is an array, then the first item in the array that matches 353 * a property that exists is returned. 354 * 355 * This method will return null if the property does not exist. 356 * 357 * @param string|array $property The name of the property (e.g. foaf:name) 358 * @param string $type The type of value to filter by (e.g. literal or resource) 359 * @param string $lang The language to filter by (e.g. en) 360 * @return mixed A value associated with the property 361 */ 362 public function get($property, $type = null, $lang = null) 363 { 364 $this->checkHasGraph(); 365 return $this->graph->get($this->uri, $property, $type, $lang); 366 } 367 368 /** Get a single literal value for a property of the resource 369 * 370 * If multiple values are set for a property then the value returned 371 * may be arbitrary. 372 * 373 * This method will return null if there is not literal value for the 374 * property. 375 * 376 * @param string|array $property The name of the property (e.g. foaf:name) 377 * @param string $lang The language to filter by (e.g. en) 378 * @return object EasyRdf_Literal Literal value associated with the property 379 */ 380 public function getLiteral($property, $lang = null) 381 { 382 $this->checkHasGraph(); 383 return $this->graph->get($this->uri, $property, 'literal', $lang); 384 } 385 386 /** Get a single resource value for a property of the resource 387 * 388 * If multiple values are set for a property then the value returned 389 * may be arbitrary. 390 * 391 * This method will return null if there is not resource for the 392 * property. 393 * 394 * @param string|array $property The name of the property (e.g. foaf:name) 395 * @return object EasyRdf_Resource Resource associated with the property 396 */ 397 public function getResource($property) 398 { 399 $this->checkHasGraph(); 400 return $this->graph->get($this->uri, $property, 'resource'); 401 } 402 403 /** Get all values for a property 404 * 405 * This method will return an empty array if the property does not exist. 406 * 407 * @param string $property The name of the property (e.g. foaf:name) 408 * @param string $type The type of value to filter by (e.g. literal) 409 * @param string $lang The language to filter by (e.g. en) 410 * @return array An array of values associated with the property 411 */ 412 public function all($property, $type = null, $lang = null) 413 { 414 $this->checkHasGraph(); 415 return $this->graph->all($this->uri, $property, $type, $lang); 416 } 417 418 /** Get all literal values for a property of the resource 419 * 420 * This method will return an empty array if the resource does not 421 * has any literal values for that property. 422 * 423 * @param string $property The name of the property (e.g. foaf:name) 424 * @param string $lang The language to filter by (e.g. en) 425 * @return array An array of values associated with the property 426 */ 427 public function allLiterals($property, $lang = null) 428 { 429 $this->checkHasGraph(); 430 return $this->graph->all($this->uri, $property, 'literal', $lang); 431 } 432 433 /** Get all resources for a property of the resource 434 * 435 * This method will return an empty array if the resource does not 436 * has any resources for that property. 437 * 438 * @param string $property The name of the property (e.g. foaf:name) 439 * @return array An array of values associated with the property 440 */ 441 public function allResources($property) 442 { 443 $this->checkHasGraph(); 444 return $this->graph->all($this->uri, $property, 'resource'); 445 } 446 447 /** Count the number of values for a property of a resource 448 * 449 * This method will return 0 if the property does not exist. 450 * 451 * @param string $property The name of the property (e.g. foaf:name) 452 * @param string $type The type of value to filter by (e.g. literal) 453 * @param string $lang The language to filter by (e.g. en) 454 * @return integer The number of values associated with the property 455 */ 456 public function countValues($property, $type = null, $lang = null) 457 { 458 $this->checkHasGraph(); 459 return $this->graph->countValues($this->uri, $property, $type, $lang); 460 } 461 462 /** Concatenate all values for a property into a string. 463 * 464 * The default is to join the values together with a space character. 465 * This method will return an empty string if the property does not exist. 466 * 467 * @param string $property The name of the property (e.g. foaf:name) 468 * @param string $glue The string to glue the values together with. 469 * @param string $lang The language to filter by (e.g. en) 470 * @return string Concatenation of all the values. 471 */ 472 public function join($property, $glue = ' ', $lang = null) 473 { 474 $this->checkHasGraph(); 475 return $this->graph->join($this->uri, $property, $glue, $lang); 476 } 477 478 /** Get a list of the full URIs for the properties of this resource. 479 * 480 * This method will return an empty array if the resource has no properties. 481 * 482 * @return array Array of full URIs 483 */ 484 public function propertyUris() 485 { 486 $this->checkHasGraph(); 487 return $this->graph->propertyUris($this->uri); 488 } 489 490 /** Get a list of all the shortened property names (qnames) for a resource. 491 * 492 * This method will return an empty array if the resource has no properties. 493 * 494 * @return array Array of shortened URIs 495 */ 496 public function properties() 497 { 498 $this->checkHasGraph(); 499 return $this->graph->properties($this->uri); 500 } 501 502 /** Get a list of the full URIs for the properties that point to this resource. 503 * 504 * @return array Array of full property URIs 505 */ 506 public function reversePropertyUris() 507 { 508 $this->checkHasGraph(); 509 return $this->graph->reversePropertyUris($this->uri); 510 } 511 512 /** Check to see if a property exists for this resource. 513 * 514 * This method will return true if the property exists. 515 * If the value parameter is given, then it will only return true 516 * if the value also exists for that property. 517 * 518 * @param string $property The name of the property (e.g. foaf:name) 519 * @param mixed $value An optional value of the property 520 * @return bool True if value the property exists. 521 */ 522 public function hasProperty($property, $value = null) 523 { 524 $this->checkHasGraph(); 525 return $this->graph->hasProperty($this->uri, $property, $value); 526 } 527 528 /** Get a list of types for a resource. 529 * 530 * The types will each be a shortened URI as a string. 531 * This method will return an empty array if the resource has no types. 532 * 533 * @return array All types assocated with the resource (e.g. foaf:Person) 534 */ 535 public function types() 536 { 537 $this->checkHasGraph(); 538 return $this->graph->types($this->uri); 539 } 540 541 /** Get a single type for a resource. 542 * 543 * The type will be a shortened URI as a string. 544 * If the resource has multiple types then the type returned 545 * may be arbitrary. 546 * This method will return null if the resource has no type. 547 * 548 * @return string A type assocated with the resource (e.g. foaf:Person) 549 */ 550 public function type() 551 { 552 $this->checkHasGraph(); 553 return $this->graph->type($this->uri); 554 } 555 556 /** Get a single type for a resource, as a resource. 557 * 558 * The type will be returned as an EasyRdf_Resource. 559 * If the resource has multiple types then the type returned 560 * may be arbitrary. 561 * This method will return null if the resource has no type. 562 * 563 * @return EasyRdf_Resource A type assocated with the resource. 564 */ 565 public function typeAsResource() 566 { 567 $this->checkHasGraph(); 568 return $this->graph->typeAsResource($this->uri); 569 } 570 571 /** 572 * Get a list of types for a resource, as Resources. 573 * 574 * @return EasyRdf_Resource[] 575 * @throws EasyRdf_Exception 576 */ 577 public function typesAsResources() 578 { 579 $this->checkHasGraph(); 580 return $this->graph->typesAsResources($this->uri); 581 } 582 583 /** Check if a resource is of the specified type 584 * 585 * @param string $type The type to check (e.g. foaf:Person) 586 * @return boolean True if resource is of specified type. 587 */ 588 public function isA($type) 589 { 590 $this->checkHasGraph(); 591 return $this->graph->isA($this->uri, $type); 592 } 593 594 /** Add one or more rdf:type properties to the resource 595 * 596 * @param string $types One or more types to add (e.g. foaf:Person) 597 * @return integer The number of types added 598 */ 599 public function addType($types) 600 { 601 $this->checkHasGraph(); 602 return $this->graph->addType($this->uri, $types); 603 } 604 605 /** Change the rdf:type property for the resource 606 * 607 * Note that the PHP class of the resource will not change. 608 * 609 * @param string $type The new type (e.g. foaf:Person) 610 * @return integer The number of types added 611 */ 612 public function setType($type) 613 { 614 $this->checkHasGraph(); 615 return $this->graph->setType($this->uri, $type); 616 } 617 618 /** Get the primary topic of this resource. 619 * 620 * Returns null if no primary topic is available. 621 * 622 * @return EasyRdf_Resource The primary topic of this resource. 623 */ 624 public function primaryTopic() 625 { 626 $this->checkHasGraph(); 627 return $this->graph->primaryTopic($this->uri); 628 } 629 630 /** Get a human readable label for this resource 631 * 632 * This method will check a number of properties for the resource 633 * (in the order: skos:prefLabel, rdfs:label, foaf:name, dc:title) 634 * and return an approriate first that is available. If no label 635 * is available then it will return null. 636 * 637 * @return string A label for the resource. 638 */ 639 public function label($lang = null) 640 { 641 $this->checkHasGraph(); 642 return $this->graph->label($this->uri, $lang); 643 } 644 645 /** Return a human readable view of the resource and its properties 646 * 647 * This method is intended to be a debugging aid and will 648 * print a resource and its properties. 649 * 650 * @param string $format Either 'html' or 'text' 651 * @return string 652 */ 653 public function dump($format = 'html') 654 { 655 $this->checkHasGraph(); 656 return $this->graph->dumpResource($this->uri, $format); 657 } 658 659 /** Magic method to get a property of a resource 660 * 661 * Note that only properties in the default namespace can be accessed in this way. 662 * 663 * Example: 664 * $value = $resource->title; 665 * 666 * @see EasyRdf_Namespace::setDefault() 667 * @param string $name The name of the property 668 * @return string A single value for the named property 669 */ 670 public function __get($name) 671 { 672 return $this->graph->get($this->uri, $name); 673 } 674 675 /** Magic method to set the value for a property of a resource 676 * 677 * Note that only properties in the default namespace can be accessed in this way. 678 * 679 * Example: 680 * $resource->title = 'Title'; 681 * 682 * @see EasyRdf_Namespace::setDefault() 683 * @param string $name The name of the property 684 * @param string $value The value for the property 685 */ 686 public function __set($name, $value) 687 { 688 return $this->graph->set($this->uri, $name, $value); 689 } 690 691 /** Magic method to check if a property exists 692 * 693 * Note that only properties in the default namespace can be accessed in this way. 694 * 695 * Example: 696 * if (isset($resource->title)) { blah(); } 697 * 698 * @see EasyRdf_Namespace::setDefault() 699 * @param string $name The name of the property 700 */ 701 public function __isset($name) 702 { 703 return $this->graph->hasProperty($this->uri, $name); 704 } 705 706 /** Magic method to delete a property of the resource 707 * 708 * Note that only properties in the default namespace can be accessed in this way. 709 * 710 * Example: 711 * unset($resource->title); 712 * 713 * @see EasyRdf_Namespace::setDefault() 714 * @param string $name The name of the property 715 */ 716 public function __unset($name) 717 { 718 return $this->graph->delete($this->uri, $name); 719 } 720} 721