Completed
Push — master ( d2d28e...1c2760 )
by mw
35:37
created

includes/dataitems/SMW_DI_Container.php (4 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
 * @ingroup SMWDataItems
4
 */
5
6
use SMW\DataItemException;
7
8
/**
9
 * Subclass of SMWSemanticData that is used to store the data in SMWDIContainer
10
 * objects. It is special since the subject that the stored property-value pairs
11
 * refer may or may not be specified explicitly. This can be tested with
12
 * hasAnonymousSubject(). When trying to access the subject in anonymous state,
13
 * an Exception will be thrown. Anonymous container data items are used when no
14
 * page context is available, e.g. when specifying such a value in a search form
15
 * where the parent page is not known.
16
 *
17
 * Besides this change, the subclass mainly is needed to restroe the disabled
18
 * serialization of SMWSemanticData.
19
 *
20
 * See also the documentation of SMWDIContainer.
21
 *
22
 * @since 1.6
23
 *
24
 * @author Markus Krötzsch
25
 * @ingroup SMWDataItems
26
 */
27
class SMWContainerSemanticData extends SMWSemanticData {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
28
29
	/**
30
	 * @var boolean
31
	 */
32
	private $skipAnonymousCheck = false;
33
34
	/**
35
	 * Construct a data container that refers to an anonymous subject. See
36
	 * the documentation of the class for details.
37
	 *
38
	 * @since 1.7
39
	 *
40
	 * @param boolean $noDuplicates stating if duplicate data should be avoided
41
	 */
42 3
	public static function makeAnonymousContainer( $noDuplicates = true, $skipAnonymousCheck = false ) {
43 3
		$subject = new SMWDIWikiPage( 'SMWInternalObject', NS_SPECIAL, '', 'int' );
44 3
		$containerSemanticData = new SMWContainerSemanticData( $subject, $noDuplicates );
45
46 3
		if ( $skipAnonymousCheck ) {
47
			$containerSemanticData->skipAnonymousCheck();
48
		}
49
50 3
		return $containerSemanticData;
51
	}
52
53
	/**
54
	 * Restore complete serialization which is disabled in SMWSemanticData.
55
	 */
56
	public function __sleep() {
57
		return array( 'mSubject', 'mProperties', 'mPropVals',
58
			'mHasVisibleProps', 'mHasVisibleSpecs', 'mNoDuplicates', 'skipAnonymousCheck' );
59
	}
60
61
	/**
62
	 * @since 2.4
63
	 */
64 3
	public function skipAnonymousCheck() {
65 3
		$this->skipAnonymousCheck = true;
66 3
	}
67
68
	/**
69
	 * Check if the subject of this container is an anonymous object.
70
	 * See the documenation of the class for details.
71
	 *
72
	 * @return boolean
73
	 */
74 138
	public function hasAnonymousSubject() {
75 138
		if ( $this->mSubject->getNamespace() == NS_SPECIAL &&
76 138
		     $this->mSubject->getDBkey() == 'SMWInternalObject' &&
77 138
		     $this->mSubject->getInterwiki() === '' &&
78 138
		     $this->mSubject->getSubobjectName() === 'int' ) {
79
			return true;
80
		} else {
81 138
			return false;
82
		}
83
	}
84
85
	/**
86
	 * Return subject to which the stored semantic annotation refer to, or
87
	 * throw an exception if the subject is anonymous (if the data has not
88
	 * been contextualized with setMasterPage() yet).
89
	 *
90
	 * @return SMWDIWikiPage subject
91
	 */
92 138
	public function getSubject() {
93
94 138
		if ( !$this->skipAnonymousCheck && $this->hasAnonymousSubject() ) {
95
			throw new DataItemException("This container has been classified as anonymous and by trying to access its subject (that has not been given any) an exception is raised to inform about the incorrect usage. An anonymous container can only be used for a search pattern match.");
96
		}
97
98 138
		return $this->mSubject;
99
	}
100
101
	/**
102
	 * Change the object to become an exact copy of the given
103
	 * SMWSemanticData object. This is used to make other types of
104
	 * SMWSemanticData into an SMWContainerSemanticData. To copy objects of
105
	 * the same type, PHP clone() should be used.
106
	 *
107
	 * @since 1.7
108
	 *
109
	 * @param $semanticData SMWSemanticData object to copy from
110
	 */
111 12
	public function copyDataFrom( SMWSemanticData $semanticData ) {
112 12
		$this->mSubject = $semanticData->getSubject();
113 12
		$this->mProperties = $semanticData->getProperties();
114 12
		$this->mPropVals = array();
115 12
		foreach ( $this->mProperties as $property ) {
116 12
			$this->mPropVals[$property->getKey()] = $semanticData->getPropertyValues( $property );
117
		}
118 12
		$this->mHasVisibleProps = $semanticData->hasVisibleProperties();
119 12
		$this->mHasVisibleSpecs = $semanticData->hasVisibleSpecialProperties();
120 12
		$this->mNoDuplicates = $semanticData->mNoDuplicates;
121 12
	}
122
123
}
124
125
/**
126
 * This class implements container data items that can store SMWSemanticData
127
 * objects. Containers are not dataitems in the proper sense: they do not
128
 * represent a single, opaque value that can be assigned to a property. Rather,
129
 * a container represents a "subobject" with a number of property-value
130
 * assignments. When a container is stored, these individual data assignments
131
 * are stored -- the data managed by SMW never contains any "container", just
132
 * individual property assignments for the subobject. Likewise, when a container
133
 * is used in search, it is interpreted as a patterns of possible property
134
 * assignments, and this pattern is searched for.
135
 *
136
 * The data encapsulated in a container data item is essentially an
137
 * SMWSemanticData object of class SMWContainerSemanticData. This class allows
138
 * the subject to be kept anonymous if not known (if no context page is
139
 * available for finding a suitable subobject name). See the repsective
140
 * documentation for details.
141
 *
142
 * Being a mere placeholder/template for other data, an SMWDIContainer is not
143
 * immutable as the other basic data items. New property-value pairs can always
144
 * be added to the internal SMWContainerSemanticData.
145
 *
146
 * @since 1.6
147
 *
148
 * @author Markus Krötzsch
149
 * @ingroup SMWDataItems
150
 */
151
class SMWDIContainer extends SMWDataItem {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
152
153
	/**
154
	 * Internal value.
155
	 *
156
	 * @var SMWSemanticData
157
	 */
158
	protected $m_semanticData;
159
160
	/**
161
	 * Constructor. The given SMWContainerSemanticData object will be owned
162
	 * by the constructed object afterwards, and in particular will not
163
	 * allow further changes.
164
	 *
165
	 * @param $semanticData SMWContainerSemanticData
166
	 */
167 138
	public function __construct( SMWContainerSemanticData $semanticData ) {
168 138
		$this->m_semanticData = $semanticData;
169 138
	}
170
171 4
	public function getDIType() {
172 4
		return SMWDataItem::TYPE_CONTAINER;
173
	}
174
175 138
	public function getSemanticData() {
176 138
		return $this->m_semanticData;
177
	}
178
179 5
	public function getSortKey() {
180 5
		return '';
181
	}
182
183
	public function getSerialization() {
184
		return serialize( $this->m_semanticData );
185
	}
186
187
	/**
188
	 * Get a hash string for this data item.
189
	 *
190
	 * @return string
191
	 */
192 1
	public function getHash() {
193
194 1
		$hash = $this->getValueHash( $this->m_semanticData );
195 1
		sort( $hash );
196
197 1
		return md5( implode( '#', $hash ) );
198
199
		// We want a value hash, not an entity hash!!
200
		// return $this->m_semanticData->getHash();
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% 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...
201
	}
202
203 1
	private function getValueHash( $semanticData ) {
204
205 1
		$hash = array();
206
207 1
		foreach ( $semanticData->getProperties() as $property ) {
208 1
			$hash[] = $property->getKey();
209
210 1
			foreach ( $semanticData->getPropertyValues( $property ) as $di ) {
211 1
				$hash[] = $di->getHash();
212
			}
213
		}
214
215 1
		foreach ( $semanticData->getSubSemanticData() as $data ) {
216
			$hash[] = $this->getValueHash( $data );
217
		}
218
219 1
		return $hash;
220
	}
221
222
	/**
223
	 * Create a data item from the provided serialization string and type
224
	 * ID.
225
	 *
226
	 * @return SMWDIContainer
227
	 */
228
	public static function doUnserialize( $serialization ) {
229
		/// TODO May issue an E_NOTICE when problems occur; catch this
230
		$data = unserialize( $serialization );
231
		if ( !( $data instanceof SMWContainerSemanticData ) ) {
232
			throw new DataItemException( "Could not unserialize SMWDIContainer from the given string." );
233
		}
234
		return new SMWDIContainer( $data );
235
	}
236
237
	public function equals( SMWDataItem $di ) {
238
		if ( $di->getDIType() !== SMWDataItem::TYPE_CONTAINER ) {
239
			return false;
240
		}
241
242
		return $di->getSerialization() === $this->getSerialization();
243
	}
244
}
245