PageRenderTime 57ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/SemanticMediaWiki/includes/SMW_SemanticData.php

#
PHP | 321 lines | 118 code | 35 blank | 168 comment | 17 complexity | 83999d41e73c1f08c2d6f6303950228c MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * The class in this file provides a container for chunks of subject-centred
  4. * data.
  5. *
  6. * @file
  7. * @ingroup SMW
  8. *
  9. * @author Markus Kr??tzsch
  10. * @author Jeroen De Dauw
  11. */
  12. /**
  13. * Class for representing chunks of semantic data for one given
  14. * article (subject), similar what is typically displayed in the Factbox.
  15. * This is a light-weight data container.
  16. *
  17. * By its very design, the container is unable to hold inverse properties.
  18. * For one thing, it would not be possible to identify them with mere keys.
  19. * Since SMW cannot annotate pages with inverses, this is not a limitation.
  20. *
  21. * @ingroup SMW
  22. */
  23. class SMWSemanticData {
  24. /**
  25. * Cache for the localized version of the namespace prefix "Property:".
  26. *
  27. * @var string
  28. */
  29. static protected $mPropertyPrefix = '';
  30. /**
  31. * States whether this is a stub object. Stubbing might happen on
  32. * serialisation to save DB space.
  33. *
  34. * @todo Check why this is public and document this here. Or fix it.
  35. *
  36. * @var boolean
  37. */
  38. public $stubObject;
  39. /**
  40. * Array mapping property keys (string) to arrays of SMWDataItem
  41. * objects.
  42. *
  43. * @var array
  44. */
  45. protected $mPropVals = array();
  46. /**
  47. * Array mapping property keys (string) to SMWDIProperty objects.
  48. *
  49. * @var array
  50. */
  51. protected $mProperties = array();
  52. /**
  53. * States whether the container holds any normal properties.
  54. *
  55. * @var boolean
  56. */
  57. protected $mHasVisibleProps = false;
  58. /**
  59. * States whether the container holds any displayable predefined
  60. * $mProperties (as opposed to predefined properties without a display
  61. * label). For some settings we need this to decide if a Factbox is
  62. * displayed.
  63. *
  64. * @var boolean
  65. */
  66. protected $mHasVisibleSpecs = false;
  67. /**
  68. * States whether repeated values should be avoided. Not needing
  69. * duplicate elimination (e.g. when loading from store) can save some
  70. * time, especially in subclasses like SMWSqlStubSemanticData, where
  71. * the first access to a data item is more costy.
  72. *
  73. * @note This setting is merely for optimization. The SMW data model
  74. * never cares about the multiplicity of identical data assignments.
  75. *
  76. * @var boolean
  77. */
  78. protected $mNoDuplicates;
  79. /**
  80. * SMWDIWikiPage object that is the subject of this container.
  81. * Subjects can never be null (and this is ensured in all methods setting
  82. * them in this class).
  83. *
  84. * @var SMWDIWikiPage
  85. */
  86. protected $mSubject;
  87. /**
  88. * Constructor.
  89. *
  90. * @param SMWDIWikiPage $subject to which this data refers
  91. * @param boolean $noDuplicates stating if duplicate data should be avoided
  92. */
  93. public function __construct( SMWDIWikiPage $subject, $noDuplicates = true ) {
  94. $this->clear();
  95. $this->mSubject = $subject;
  96. $this->mNoDuplicates = $noDuplicates;
  97. }
  98. /**
  99. * This object is added to the parser output of MediaWiki, but it is
  100. * not useful to have all its data as part of the parser cache since
  101. * the data is already stored in more accessible format in SMW. Hence
  102. * this implementation of __sleep() makes sure only the subject is
  103. * serialised, yielding a minimal stub data container after
  104. * unserialisation. This is a little safer than serialising nothing:
  105. * if, for any reason, SMW should ever access an unserialised parser
  106. * output, then the Semdata container will at least look as if properly
  107. * initialised (though empty).
  108. *
  109. * @return array
  110. */
  111. public function __sleep() {
  112. return array( 'mSubject' );
  113. }
  114. /**
  115. * Return subject to which the stored semantic annotations refer to.
  116. *
  117. * @return SMWDIWikiPage subject
  118. */
  119. public function getSubject() {
  120. return $this->mSubject;
  121. }
  122. /**
  123. * Get the array of all properties that have stored values.
  124. *
  125. * @return array of SMWDIProperty objects
  126. */
  127. public function getProperties() {
  128. ksort( $this->mProperties, SORT_STRING );
  129. return $this->mProperties;
  130. }
  131. /**
  132. * Get the array of all stored values for some property.
  133. *
  134. * @param $property SMWDIProperty
  135. * @return array of SMWDataItem
  136. */
  137. public function getPropertyValues( SMWDIProperty $property ) {
  138. if ( $property->isInverse() ) { // we never have any data for inverses
  139. return array();
  140. }
  141. if ( array_key_exists( $property->getKey(), $this->mPropVals ) ) {
  142. return $this->mPropVals[$property->getKey()];
  143. } else {
  144. return array();
  145. }
  146. }
  147. /**
  148. * Generate a hash value to simplify the comparison of this data
  149. * container with other containers. The hash uses PHP's md5
  150. * implementation, which is among the fastest hash algorithms that
  151. * PHP offers.
  152. *
  153. * @return string
  154. */
  155. public function getHash() {
  156. $ctx = hash_init( 'md5' );
  157. // here and below, use "_#_" to separate values; really not much care needed here
  158. hash_update( $ctx, '_#_' . $this->mSubject->getSerialization() );
  159. foreach ( $this->getProperties() as $property ) {
  160. hash_update( $ctx, '_#_' . $property->getKey() . '##' );
  161. foreach ( $this->getPropertyValues( $property ) as $di ) {
  162. hash_update( $ctx, '_#_' . $di->getSerialization() );
  163. }
  164. }
  165. return hash_final( $ctx );
  166. }
  167. /**
  168. * Return true if there are any visible properties.
  169. *
  170. * @note While called "visible" this check actually refers to the
  171. * function SMWDIProperty::isShown(). The name is kept for
  172. * compatibility.
  173. *
  174. * @return boolean
  175. */
  176. public function hasVisibleProperties() {
  177. return $this->mHasVisibleProps;
  178. }
  179. /**
  180. * Return true if there are any special properties that can
  181. * be displayed.
  182. *
  183. * @note While called "visible" this check actually refers to the
  184. * function SMWDIProperty::isShown(). The name is kept for
  185. * compatibility.
  186. *
  187. * @return boolean
  188. */
  189. public function hasVisibleSpecialProperties() {
  190. return $this->mHasVisibleSpecs;
  191. }
  192. /**
  193. * Store a value for a property identified by its SMWDataItem object.
  194. *
  195. * @note There is no check whether the type of the given data item
  196. * agrees with the type of the property. Since property types can
  197. * change, all parts of SMW are prepared to handle mismatched data item
  198. * types anyway.
  199. *
  200. * @param $property SMWDIProperty
  201. * @param $dataItem SMWDataItem
  202. */
  203. public function addPropertyObjectValue( SMWDIProperty $property, SMWDataItem $dataItem ) {
  204. if ( $property->isInverse() ) { // inverse properties cannot be used for annotation
  205. return;
  206. }
  207. if ( !array_key_exists( $property->getKey(), $this->mPropVals ) ) {
  208. $this->mPropVals[$property->getKey()] = array();
  209. $this->mProperties[$property->getKey()] = $property;
  210. }
  211. if ( $this->mNoDuplicates ) {
  212. $this->mPropVals[$property->getKey()][$dataItem->getHash()] = $dataItem;
  213. } else {
  214. $this->mPropVals[$property->getKey()][] = $dataItem;
  215. }
  216. if ( !$property->isUserDefined() ) {
  217. if ( $property->isShown() ) {
  218. $this->mHasVisibleSpecs = true;
  219. $this->mHasVisibleProps = true;
  220. }
  221. } else {
  222. $this->mHasVisibleProps = true;
  223. }
  224. }
  225. /**
  226. * Store a value for a given property identified by its text label
  227. * (without namespace prefix).
  228. *
  229. * @param $propertyName string
  230. * @param $dataItem SMWDataItem
  231. */
  232. public function addPropertyValue( $propertyName, SMWDataItem $dataItem ) {
  233. $propertyKey = smwfNormalTitleDBKey( $propertyName );
  234. if ( array_key_exists( $propertyKey, $this->mProperties ) ) {
  235. $property = $this->mProperties[$propertyKey];
  236. } else {
  237. if ( self::$mPropertyPrefix === '' ) {
  238. global $wgContLang;
  239. self::$mPropertyPrefix = $wgContLang->getNsText( SMW_NS_PROPERTY ) . ':';
  240. } // explicitly use prefix to cope with things like [[Property:User:Stupid::somevalue]]
  241. $propertyDV = SMWPropertyValue::makeUserProperty( self::$mPropertyPrefix . $propertyName );
  242. if ( !$propertyDV->isValid() ) { // error, maybe illegal title text
  243. return;
  244. }
  245. $property = $propertyDV->getDataItem();
  246. }
  247. $this->addPropertyObjectValue( $property, $dataItem );
  248. }
  249. /**
  250. * Delete all data other than the subject.
  251. */
  252. public function clear() {
  253. $this->mPropVals = array();
  254. $this->mProperties = array();
  255. $this->mHasVisibleProps = false;
  256. $this->mHasVisibleSpecs = false;
  257. $this->stubObject = false;
  258. }
  259. /**
  260. * Add all data from the given SMWSemanticData.
  261. *
  262. * @since 1.7
  263. *
  264. * @param $semanticData SMWSemanticData object to copy from
  265. */
  266. public function importDataFrom( SMWSemanticData $semanticData ) {
  267. // Shortcut when copying into empty objects that don't ask for more duplicate elimination:
  268. if ( count( $this->mProperties ) == 0 &&
  269. ( $semanticData->mNoDuplicates >= $this->mNoDuplicates ) ) {
  270. $this->mProperties = $semanticData->getProperties();
  271. $this->mPropVals = array();
  272. foreach ( $this->mProperties as $property ) {
  273. $this->mPropVals[$property->getKey()] = $semanticData->getPropertyValues( $property );
  274. }
  275. $this->mHasVisibleProps = $semanticData->hasVisibleProperties();
  276. $this->mHasVisibleSpecs = $semanticData->hasVisibleSpecialProperties();
  277. } else {
  278. foreach ( $semanticData->getProperties() as $property ) {
  279. $values = $semanticData->getPropertyValues( $property );
  280. foreach ( $values as $dataItem ) {
  281. $this->addPropertyObjectValue( $property, $dataItem);
  282. }
  283. }
  284. }
  285. }
  286. }