Completed
Push — master ( 470987...2214a8 )
by mw
32:06
created

SubSemanticData::copyDataFrom()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SMW\DataModel;
4
5
use SMW\Exception\SubSemanticDataException;
6
use SMW\SemanticData;
7
use SMW\DIWikiPage;
8
9
/**
10
 * @private
11
 *
12
 * Internal handling of the SubSemanticData container and its subsequent
13
 * add and remove operations.
14
 *
15
 * @license GNU GPL v2+
16
 * @since 2.5
17
 *
18
 * @author Markus Krötzsch
19
 * @author Jeroen De Dauw
20
 * @author mwjames
21
 */
22
class SubSemanticData {
23
24
	/**
25
	 * States whether repeated values should be avoided. Not needing
26
	 * duplicate elimination (e.g. when loading from store) can save some
27
	 * time, especially in subclasses like SMWSqlStubSemanticData, where
28
	 * the first access to a data item is more costy.
29
	 *
30
	 * @note This setting is merely for optimization. The SMW data model
31
	 * never cares about the multiplicity of identical data assignments.
32
	 *
33
	 * @var boolean
34
	 */
35
	private $noDuplicates;
36
37
	/**
38
	 * DIWikiPage object that is the subject of this container.
39
	 * Subjects can never be null (and this is ensured in all methods setting
40
	 * them in this class).
41
	 *
42
	 * @var DIWikiPage
43
	 */
44
	private $subject;
45
46
	/**
47
	 * Semantic data associated to subobjects of the subject of this
48
	 * SMWSemanticData.
49
	 * These key-value pairs of subObjectName (string) =>SMWSemanticData.
50
	 *
51
	 * @since 2.5
52
	 * @var SemanticData[]
53
	 */
54
	private $subSemanticData = array();
55
56
	/**
57
	 * Internal flag that indicates if this semantic data will accept
58
	 * subdata. Semantic data objects that are subdata already do not allow
59
	 * (second level) subdata to be added. This ensures that all data is
60
	 * collected on the top level, and in particular that there is only one
61
	 * way to represent the same data with subdata. This is also useful for
62
	 * diff computation.
63
	 *
64
	 * @var boolean
65
	 */
66
	private $subDataAllowed = true;
0 ignored issues
show
Unused Code introduced by
The property $subDataAllowed is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
67
68
	/**
69
	 * Maximum depth for an recursive sub data assignment
70
	 *
71
	 * @var integer
72
	 */
73
	private $subContainerMaxDepth = 3;
74
75
	/**
76
	 * @var integer
77
	 */
78
	private $subContainerDepthCounter = 0;
0 ignored issues
show
Unused Code introduced by
The property $subContainerDepthCounter is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
79
80
	/**
81
	 * Constructor.
82
	 *
83
	 * @param DIWikiPage $subject to which this data refers
84
	 * @param boolean $noDuplicates stating if duplicate data should be avoided
85
	 */
86 302
	public function __construct( DIWikiPage $subject, $noDuplicates = true ) {
87 302
		$this->clear();
88 302
		$this->subject = $subject;
89 302
		$this->noDuplicates = $noDuplicates;
90 302
	}
91
92
	/**
93
	 * This object is added to the parser output of MediaWiki, but it is
94
	 * not useful to have all its data as part of the parser cache since
95
	 * the data is already stored in more accessible format in SMW. Hence
96
	 * this implementation of __sleep() makes sure only the subject is
97
	 * serialised, yielding a minimal stub data container after
98
	 * unserialisation. This is a little safer than serialising nothing:
99
	 * if, for any reason, SMW should ever access an unserialised parser
100
	 * output, then the Semdata container will at least look as if properly
101
	 * initialised (though empty).
102
	 *
103
	 * @return array
104
	 */
105 274
	public function __sleep() {
106 274
		return array( 'subject', 'subSemanticData' );
107
	}
108
109
	/**
110
	 * Return subject to which the stored semantic annotations refer to.
111
	 *
112
	 * @return DIWikiPage subject
113
	 */
114 167
	public function getSubject() {
115 167
		return $this->subject;
116
	}
117
118
	/**
119
	 * This is used as contingency where the serialized SementicData still
120
	 * has an array object reference.
121
	 *
122
	 * @since 2.5
123
	 *
124
	 * @return ContainerSemanticData[]
125
	 */
126
	public function copyDataFrom( array $subSemanticData ) {
127
		$this->subSemanticData = $subSemanticData;
128
	}
129
130
	/**
131
	 * Return the array of subSemanticData objects in form of
132
	 * subobjectName => ContainerSemanticData
133
	 *
134
	 * @since 2.5
135
	 *
136
	 * @return ContainerSemanticData[]
137
	 */
138 288
	public function getSubSemanticData() {
139 288
		return $this->subSemanticData;
140
	}
141
142
	/**
143
	 * @since 2.5
144
	 */
145 302
	public function clear() {
146 302
		$this->subSemanticData = array();
147 302
	}
148
149
	/**
150
	 * @since 2.5
151
	 *
152
	 * @param string $subobjectName|null
0 ignored issues
show
Documentation introduced by
There is no parameter named $subobjectName|null. Did you maybe mean $subobjectName?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
153
	 *
154
	 * @return boolean
155
	 */
156 167
	public function hasSubSemanticData( $subobjectName = null ) {
157
158 167
		if ( $this->subSemanticData === array() || $subobjectName === '' ) {
159 167
			return false;
160
		}
161
162 119
		return $subobjectName !== null ? isset( $this->subSemanticData[$subobjectName] ) : true;
163
	}
164
165
	/**
166
	 * Find a particular subobject container using its name as identifier
167
	 *
168
	 * @since 2.5
169
	 *
170
	 * @param string $subobjectName
171
	 *
172
	 * @return ContainerSemanticData|[]
0 ignored issues
show
Documentation introduced by
The doc-type ContainerSemanticData|[] could not be parsed: Unknown type name "" at position 22. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
173
	 */
174 4
	public function findSubSemanticData( $subobjectName ) {
175
176 4
		if ( $this->hasSubSemanticData( $subobjectName ) && isset( $this->subSemanticData[$subobjectName] ) ) {
177 4
			return $this->subSemanticData[$subobjectName];
178
		}
179
180 2
		return array();
181
	}
182
183
	/**
184
	 * Add data about subobjects
185
	 *
186
	 * Will only work if the data that is added is about a subobject of
187
	 * this SMWSemanticData's subject. Otherwise an exception is thrown.
188
	 * The SMWSemanticData object that is given will belong to this object
189
	 * after the operation; it should not be modified further by the caller.
190
	 *
191
	 * @since 2.5
192
	 *
193
	 * @param SemanticData $semanticData
194
	 *
195
	 * @throws SubSemanticDataException if not adding data about a subobject of this data
196
	 */
197 167
	public function addSubSemanticData( SemanticData $semanticData ) {
198
199
	//	$semanticData->setLastModified( $this->getLastModified() );
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
200 167
		$this->hash = null;
0 ignored issues
show
Bug introduced by
The property hash does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
201
202 167
		if ( $semanticData->subContainerDepthCounter > $this->subContainerMaxDepth ) {
203
			throw new SubSemanticDataException( "Cannot add further subdata with the depth of {$semanticData->subContainerDepthCounter}. You are trying to add data beyond the max depth of {$this->subContainerMaxDepth} to an SemanticData object." );
204
		}
205
206 167
		$subobjectName = $semanticData->getSubject()->getSubobjectName();
207
208 167
		if ( $subobjectName == '' ) {
209
			throw new SubSemanticDataException( "Cannot add data that is not about a subobject." );
210
		}
211
212 167
		if ( $semanticData->getSubject()->getDBkey() !== $this->getSubject()->getDBkey() ) {
213 1
			throw new SubSemanticDataException( "Data for a subobject of {$semanticData->getSubject()->getDBkey()} cannot be added to {$this->getSubject()->getDBkey()}." );
214
		}
215
216 166
		if ( $this->hasSubSemanticData( $subobjectName ) ) {
217 10
			$this->subSemanticData[$subobjectName]->importDataFrom( $semanticData );
218
219 10
			foreach ( $semanticData->getSubSemanticData() as $containerSemanticData ) {
220 10
				$this->addSubSemanticData( $containerSemanticData );
221
			}
222
		} else {
223 166
			$semanticData->subContainerDepthCounter++;
224 166
			foreach ( $semanticData->getSubSemanticData() as $containerSemanticData ) {
225
226
				// Skip container that are known to be registered (avoids recursive statement extension)
227 17
				if ( $this->hasSubSemanticData( $containerSemanticData->getSubject()->getSubobjectName() ) ) {
228 5
					continue;
229
				}
230
231 13
				$this->addSubSemanticData( $containerSemanticData );
232
			}
233
234 166
			$semanticData->clearSubSemanticData();
235 166
			$this->subSemanticData[$subobjectName] = $semanticData;
236
		}
237 166
	}
238
239
	/**
240
	* Remove data about a subobject
241
	*
242
	* If the removed data is not about a subobject of this object,
243
	* it will silently be ignored (nothing to remove). Likewise,
244
	* removing data that is not present does not change anything.
245
	*
246
	* @since 2.5
247
	*
248
	* @param SemanticData $semanticData
249
	*/
250 1
	public function removeSubSemanticData( SemanticData $semanticData ) {
251
252 1
		if ( $semanticData->getSubject()->getDBkey() !== $this->getSubject()->getDBkey() ) {
253
			return;
254
		}
255
256 1
		$subobjectName = $semanticData->getSubject()->getSubobjectName();
257
258 1
		if ( $this->hasSubSemanticData( $subobjectName ) ) {
259 1
			$this->subSemanticData[$subobjectName]->removeDataFrom( $semanticData );
260
261 1
			if ( $this->subSemanticData[$subobjectName]->isEmpty() ) {
262 1
				unset( $this->subSemanticData[$subobjectName] );
263
			}
264
		}
265 1
	}
266
267
}
268