Completed
Push — master ( 14d2bd...06e609 )
by mw
81:37 queued 59:24
created

includes/export/SMW_Exp_Data.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
use SMW\Exporter\Element;
4
5
/**
6
 * SMWExpData is a class representing semantic data that is ready for easy
7
 * serialisation in OWL or RDF.
8
 *
9
 * @author Markus Krötzsch
10
 * @ingroup SMW
11
 */
12
13
14
15
/**
16
 * SMWExpData is a data container for export-ready semantic content. It is
17
 * organised as a tree-shaped data structure with one root subject and zero
18
 * or more children connected with labelled edges to the root. Children are
19
 * again SMWExpData objects, and edges are annotated with SMWExpNsElements
20
 * specifying properties.
21
 * @note We do not allow property element without namespace abbreviation
22
 * here. Property aabbreviations are mandatory for some serialisations.
23
 *
24
 * @ingroup SMW
25
 */
26
class SMWExpData implements Element {
27
28
	/**
29
	 * @var DataItem|null
30
	 */
31
	private $dataItem;
32
33
	/**
34
	 * The subject of the data that we store.
35
	 * @var SMWExpResource
36
	 */
37
	protected $m_subject;
38
39
	/**
40
	 * Array mapping property URIs to arrays their values, given as
41
	 * SMWExpElement objects.
42
	 * @var array of array of SMWElement
43
	 */
44
	protected $m_children = array();
45
46
	/**
47
	 * Array mapping property URIs to arrays their SMWExpResource
48
	 * @var array of SMWExpResource
49
	 */
50
	protected $m_edges = array();
51
52
	/**
53
	 * @var string|null
54
	 */
55
	private $hash = null;
56
57
	/**
58
	 * Constructor. $subject is the SMWExpResource for the
59
	 * subject about which this SMWExpData is.
60
	 */
61 14
	public function __construct( SMWExpResource $subject ) {
62 14
		$this->dataItem = $subject->getDataItem();
63 14
		$this->m_subject = $subject;
64 14
	}
65
66
	/**
67
	 * @since 2.2
68
	 *
69
	 * @return DataItem|null
70
	 */
71
	public function getDataItem() {
72
		return $this->dataItem;
73
	}
74
75
	/**
76
	 * @since 2.2
77
	 *
78
	 * @return string
79
	 */
80 7
	public function getHash() {
81
82 7
		if ( $this->hash !== null ) {
83
			return $this->hash;
84
		}
85
86 7
		$hashes = array();
87 7
		$hashes[] = $this->m_subject->getHash();
88
89 7
		foreach ( $this->getProperties() as $property ) {
90
91 6
			$hashes[] = $property->getHash();
92
93 6
			foreach ( $this->getValues( $property ) as $child ) {
94 6
				$hashes[] = $child->getHash();
95
			}
96
		}
97
98 7
		sort( $hashes );
99
100 7
		$this->hash = md5( implode( '#', $hashes ) );
101 7
		unset( $hashes );
102
103 7
		return $this->hash;
104
	}
105
106
	/**
107
	 * Turn an array of SMWExpElements into an RDF collection.
108
	 *
109
	 * @param $elements array of SMWExpElement
110
	 * @return SMWExpData
111
	 */
112
	public static function makeCollection( array $elements ) {
113
114
		if ( count( $elements ) == 0 ) {
115
			return new SMWExpData( SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'nil' ) );
116
		}
117
118
		$result = new SMWExpData( new SMWExpResource( '' ) ); // bnode
119
120
		$result->addPropertyObjectValue(
121
			SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'type' ),
122
			new SMWExpData( SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'List' ) )
123
		);
124
125
		$result->addPropertyObjectValue(
126
			SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'first' ),
127
			array_shift( $elements )
128
		);
129
130
		$result->addPropertyObjectValue(
131
			SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'rest' ),
132
			self::makeCollection( $elements )
133
		);
134
135
		return $result;
136
	}
137
138
	/**
139
	 * Return subject to which the stored semantic annotation refer to.
140
	 *
141
	 * @return SMWExpResource
142
	 */
143 13
	public function getSubject() {
144 13
		return $this->m_subject;
145
	}
146
147
	/**
148
	 * Store a value for a property identified by its title object. No
149
	 * duplicate elimination as this is usually done in SMWSemanticData
150
	 * already (which is typically used to generate this object).
151
	 *
152
	 * @param SMWExpNsResource $property
153
	 * @param Element $child
154
	 */
155 13
	public function addPropertyObjectValue( SMWExpNsResource $property, Element $child ) {
156
157 13
		$this->hash = null;
158
159 13
		if ( !array_key_exists( $property->getUri(), $this->m_edges ) ) {
160 13
			$this->m_children[$property->getUri()] = array();
161 13
			$this->m_edges[$property->getUri()] = $property;
162
		}
163
164 13
		$this->m_children[$property->getUri()][] = $child;
165 13
	}
166
167
	/**
168
	 * Return the list of SMWExpResource objects for all properties for
169
	 * which some values have been given.
170
	 *
171
	 * @return array of SMWExpResource
172
	 */
173 18
	public function getProperties() {
174 18
		return $this->m_edges;
175
	}
176
177
	/**
178
	 * Return the list of SMWExpElement values associated to some property
179
	 * (element).
180
	 *
181
	 * @return array of SMWExpElement
182
	 */
183 17
	public function getValues( SMWExpResource $property ) {
184
185 17
		if ( array_key_exists( $property->getUri(), $this->m_children ) ) {
186 17
			return $this->m_children[$property->getUri()];
187
		}
188
189
		return array();
190
	}
191
192
	/**
193
	 * Return the list of SMWExpData values associated to some property that is
194
	 * specifed by a standard namespace id and local name.
195
	 *
196
	 * @param $namespaceId string idetifying a known special namespace (e.g. "rdf")
197
	 * @param $localName string of local name (e.g. "type")
198
	 * @return array of SMWExpData
199
	 */
200 13
	public function getSpecialValues( $namespaceId, $localName ) {
201 13
		$pe = SMWExporter::getInstance()->getSpecialNsResource( $namespaceId, $localName );
202 13
		return $this->getValues( $pe );
203
	}
204
205
	/**
206
	 * This function finds the main type (class) element of the subject
207
	 * based on the current property assignments. It returns this type
208
	 * element (SMWExpElement) and removes the according type assignement
209
	 * from the data. If no type is assigned, the element for rdf:Resource
210
	 * is returned.
211
	 *
212
	 * @note Under all normal conditions, the result will be an
213
	 * SMWExpResource.
214
	 *
215
	 * @return SMWExpElement
216
	 */
217 13
	public function extractMainType() {
218 13
		$pe = SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'type' );
219 13
		if ( array_key_exists( $pe->getUri(), $this->m_children ) ) {
220 13
			$result = array_shift( $this->m_children[$pe->getUri()] );
221 13
			if ( count( $this->m_children[$pe->getUri()] ) == 0 ) {
222 13
				unset( $this->m_edges[$pe->getUri()] );
223 13
				unset( $this->m_children[$pe->getUri()] );
224
			}
225 13
			return ( $result instanceof SMWExpData ) ? $result->getSubject() : $result;
226
		} else {
227
			return SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'Resource' );
228
		}
229
	}
230
231
	/**
232
	 * Check if this element encodes an RDF list, and if yes return an
233
	 * array of SMWExpElements corresponding to the collection elements in
234
	 * the specified order. Otherwise return false.
235
	 * The method only returns lists that can be encoded using
236
	 * parseType="Collection" in RDF/XML, i.e. only lists of non-literal
237
	 * resources.
238
	 *
239
	 * @return mixed array of SMWExpElement (but not SMWExpLiteral) or false
240
	 */
241 1
	public function getCollection() {
242 1
		$rdftypeUri  = SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'type' )->getUri();
243 1
		$rdffirstUri = SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'first' )->getUri();
244 1
		$rdfrestUri  = SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'rest' )->getUri();
245 1
		$rdfnilUri   = SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'nil' )->getUri();
246
		// first check if we are basically an RDF List:
247 1
		if ( ( $this->m_subject->isBlankNode() ) &&
248 1
		     ( count( $this->m_children ) == 3 ) &&
249 1
		     ( array_key_exists( $rdftypeUri, $this->m_children ) ) &&
250 1
		     ( count( $this->m_children[$rdftypeUri] ) == 1 ) &&
251 1
		     ( array_key_exists( $rdffirstUri, $this->m_children ) ) &&
252 1
		     ( count( $this->m_children[$rdffirstUri] ) == 1 ) &&
253 1
		     !( end( $this->m_children[$rdffirstUri] ) instanceof SMWExpLiteral ) &&
0 ignored issues
show
The class SMWExpLiteral does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
254
		     // (parseType collection in RDF not possible with literals :-/)
255 1
		     ( array_key_exists( $rdfrestUri, $this->m_children ) ) &&
256 1
		     ( count( $this->m_children[$rdfrestUri] ) == 1 ) ) {
257
			$typedata = end( $this->m_children[$rdftypeUri] );
258
			$rdflistUri = SMWExporter::getInstance()->getSpecialNsResource( 'rdf', 'List' )->getUri();
259
			if ( $typedata->getSubject()->getUri() == $rdflistUri ) {
260
				$first = end( $this->m_children[$rdffirstUri] );
261
				$rest  = end( $this->m_children[$rdfrestUri] );
262
				if ( $rest instanceof SMWExpData ) {
263
					$restlist = $rest->getCollection();
264
					if ( $restlist === false ) {
265
						return false;
266
					} else {
267
						array_unshift( $restlist, $first );
268
						return $restlist;
269
					}
270
				} elseif ( ( $rest instanceof SMWExpResource ) &&
271
				           ( $rest->getUri() == $rdfnilUri ) )  {
272
					return array( $first );
273
				} else {
274
					return false;
275
				}
276
			} else {
277
				return false;
278
			}
279 1
		} elseif ( ( count( $this->m_children ) == 0 ) && ( $this->m_subject->getUri() == $rdfnilUri ) ) {
280
			return array();
281
		} else {
282 1
			return false;
283
		}
284
	}
285
286
	/**
287
	 * Return an array of ternary arrays (subject predicate object) of
288
	 * SMWExpElements that represents the flattened version of this data.
289
	 *
290
	 * @return array of array of SMWExpElement
291
	 */
292
	public function getTripleList( Element $subject = null ) {
293
		global $smwgBnodeCount;
294
		if ( !isset( $smwgBnodeCount ) ) {
295
			$smwgBnodeCount = 0;
296
		}
297
298
		if ( $subject == null ) {
299
			$subject = $this->m_subject;
300
		}
301
302
		$result = array();
303
304
		foreach ( $this->m_edges as $key => $edge ) {
305
			foreach ( $this->m_children[$key] as $childElement ) {
306
				if ( $childElement instanceof SMWExpData ) {
307
					$childSubject = $childElement->getSubject();
308
				} else {
309
					$childSubject = $childElement;
310
				}
311
312
				if ( ( $childSubject instanceof SMWExpResource ) &&
0 ignored issues
show
The class SMWExpResource does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
313
				     ( $childSubject->isBlankNode() ) ) { // bnode, rename ID to avoid unifying bnodes of different contexts
314
					// TODO: should we really rename bnodes of the form "_id" here?
315
					$childSubject = new SMWExpResource( '_' . $smwgBnodeCount++, $childSubject->getDataItem() );
316
				}
317
318
				$result[] = array( $subject, $edge, $childSubject );
319
				if ( $childElement instanceof SMWExpData ) { // recursively add child's triples
320
					$result = array_merge( $result, $childElement->getTripleList( $childSubject ) );
321
				}
322
			}
323
		}
324
325
		return $result;
326
	}
327
328
}
329