These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace SMW\DataValues; |
||
4 | |||
5 | use SMW\ApplicationFactory; |
||
6 | use SMW\DataValueFactory; |
||
7 | use SMW\DataValues\ValueFormatters\DataValueFormatter; |
||
8 | use SMW\DIProperty; |
||
9 | use SMW\DIWikiPage; |
||
10 | use SMW\Message; |
||
11 | use SMWContainerSemanticData as ContainerSemanticData; |
||
12 | use SMWDataItem as DataItem; |
||
13 | use SMWDataValue as DataValue; |
||
14 | use SMWDIContainer as DIContainer; |
||
15 | use SMWPropertyListValue as PropertyListValue; |
||
16 | |||
17 | /** |
||
18 | * ReferenceValue allows to define additional DV to describe the state of a |
||
19 | * SourceValue in terms of provenance or referential evidence. ReferenceValue is |
||
20 | * stored as separate entity to the original subject in order to encapsulate the |
||
21 | * SourceValue from the remaining annotations kept in reference to a subject. |
||
22 | * |
||
23 | * Defining which fields are required can vary and therefore is left to the user |
||
24 | * to specify such requirements using the `'Has fields' property. |
||
25 | * |
||
26 | * For example, declaring `[[Has fields::SomeValue;Date;SomeUrl;...]]` on a |
||
27 | * `SomeProperty` property page is to define: |
||
28 | * |
||
29 | * - a property called `SomeValue` with its own specification |
||
30 | * - a date property with the Date type |
||
31 | * - a property called `SomeUrl` with its own specification |
||
32 | * - ... any other property the users expects to require when making a value |
||
33 | * annotation of this type |
||
34 | * |
||
35 | * An annotation `[[SomeProperty::Foo;12-12-1212;http://example.org]]` is expected |
||
36 | * to be a concatenated string and be separated by ';' to indicate the next value |
||
37 | * string which will corespondent to the index of the `Has fields` declaration. |
||
38 | * |
||
39 | * @license GNU GPL v2+ |
||
40 | * @since 2.5 |
||
41 | * |
||
42 | * @author mwjames |
||
43 | */ |
||
44 | class ReferenceValue extends AbstractMultiValue { |
||
45 | |||
46 | /** |
||
47 | * @var DIProperty[]|null |
||
48 | */ |
||
49 | private $properties = null; |
||
50 | |||
51 | /** |
||
52 | * @param string $typeid |
||
53 | */ |
||
54 | 8 | public function __construct( $typeid = '' ) { |
|
55 | 8 | parent::__construct( '_ref_rec' ); |
|
56 | 8 | } |
|
57 | |||
58 | /** |
||
59 | * @since 2.5 |
||
60 | * |
||
61 | * {@inheritDoc} |
||
62 | */ |
||
63 | public function setFieldProperties( array $properties ) { |
||
64 | foreach ( $properties as $property ) { |
||
65 | if ( $property instanceof DIProperty ) { |
||
66 | $this->properties[] = $property; |
||
67 | } |
||
68 | } |
||
69 | } |
||
70 | |||
71 | /** |
||
72 | * @since 2.5 |
||
73 | * |
||
74 | * {@inheritDoc} |
||
75 | */ |
||
76 | public function getProperties() { |
||
77 | return $this->properties; |
||
0 ignored issues
–
show
Bug
Compatibility
introduced
by
Loading history...
|
|||
78 | } |
||
79 | |||
80 | /** |
||
81 | * @since 2.5 |
||
82 | * |
||
83 | * {@inheritDoc} |
||
84 | */ |
||
85 | 5 | public function getValuesFromString( $value ) { |
|
86 | // #664 / T17732 |
||
87 | 5 | $value = str_replace( "\;", "-3B", $value ); |
|
88 | |||
89 | // Bug 21926 / T23926 |
||
90 | // Values that use html entities are encoded with a semicolon |
||
91 | 5 | $value = htmlspecialchars_decode( $value, ENT_QUOTES ); |
|
92 | 5 | $values = preg_split( '/[\s]*;[\s]*/u', trim( $value ) ); |
|
93 | |||
94 | 5 | return str_replace( "-3B", ";", $values ); |
|
95 | } |
||
96 | |||
97 | /** |
||
98 | * @see DataValue::getShortWikiText |
||
99 | * @since 2.5 |
||
100 | * |
||
101 | * {@inheritDoc} |
||
102 | */ |
||
103 | 2 | public function getShortWikiText( $linker = null ) { |
|
104 | 2 | return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_SHORT, $linker ); |
|
105 | } |
||
106 | |||
107 | /** |
||
108 | * @see DataValue::getShortHTMLText |
||
109 | * @since 2.5 |
||
110 | * |
||
111 | * {@inheritDoc} |
||
112 | */ |
||
113 | public function getShortHTMLText( $linker = null ) { |
||
114 | return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_SHORT, $linker ); |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * @see DataValue::getLongWikiText |
||
119 | * @since 2.5 |
||
120 | * |
||
121 | * {@inheritDoc} |
||
122 | */ |
||
123 | public function getLongWikiText( $linker = null ) { |
||
124 | return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_LONG, $linker ); |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * @see DataValue::getLongHTMLText |
||
129 | * @since 2.5 |
||
130 | * |
||
131 | * {@inheritDoc} |
||
132 | */ |
||
133 | public function getLongHTMLText( $linker = null ) { |
||
134 | return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_LONG, $linker ); |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * @see DataValue::getWikiValue |
||
139 | * @since 2.5 |
||
140 | * |
||
141 | * {@inheritDoc} |
||
142 | */ |
||
143 | 1 | public function getWikiValue() { |
|
144 | 1 | return $this->getDataValueFormatter()->format( DataValueFormatter::VALUE ); |
|
145 | } |
||
146 | |||
147 | /** |
||
148 | * @since 2.5 |
||
149 | * |
||
150 | * {@inheritDoc} |
||
151 | */ |
||
152 | 5 | public function getPropertyDataItems() { |
|
153 | |||
154 | 5 | if ( $this->properties === null ) { |
|
155 | 5 | $this->properties = $this->findPropertyDataItems( $this->getProperty() ); |
|
156 | |||
157 | 5 | if ( count( $this->properties ) == 0 ) { |
|
158 | $this->addErrorMsg( array( 'smw-datavalue-reference-invalid-fields-definition' ), Message::PARSE ); |
||
159 | } |
||
160 | } |
||
161 | |||
162 | 5 | return $this->properties; |
|
0 ignored issues
–
show
The return type of
return $this->properties; (array ) is incompatible with the return type declared by the abstract method SMW\DataValues\AbstractM...e::getPropertyDataItems of type SMW\DataValues\DIProperty[]|null .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
163 | } |
||
164 | |||
165 | /** |
||
166 | * @since 2.5 |
||
167 | * |
||
168 | * {@inheritDoc} |
||
169 | */ |
||
170 | public function getDataItems() { |
||
171 | return parent::getDataItems(); |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * @note called by DataValue::setUserValue |
||
176 | * @see DataValue::parseUserValue |
||
177 | * |
||
178 | * {@inheritDoc} |
||
179 | */ |
||
180 | 5 | protected function parseUserValue( $value ) { |
|
181 | |||
182 | 5 | if ( $value === '' ) { |
|
183 | 1 | $this->addErrorMsg( array( 'smw_novalues' ) ); |
|
184 | 1 | return; |
|
185 | } |
||
186 | |||
187 | 4 | $containerSemanticData = $this->newContainerSemanticData( $value ); |
|
188 | 4 | $sortKeys = array(); |
|
189 | |||
190 | 4 | $values = $this->getValuesFromString( $value ); |
|
191 | 4 | $index = 0; // index in value array |
|
192 | |||
193 | 4 | $propertyIndex = 0; // index in property list |
|
194 | 4 | $empty = true; |
|
195 | |||
196 | 4 | foreach ( $this->getPropertyDataItems() as $property ) { |
|
197 | |||
198 | 4 | if ( !array_key_exists( $index, $values ) || $this->getErrors() !== array() ) { |
|
199 | 1 | break; // stop if there are no values left |
|
200 | } |
||
201 | |||
202 | // generating the DVs: |
||
203 | 4 | if ( ( $values[$index] === '' ) || ( $values[$index] == '?' ) ) { // explicit omission |
|
204 | $index++; |
||
205 | } else { |
||
206 | 4 | $dataValue = DataValueFactory::getInstance()->newDataValueByProperty( |
|
207 | $property, |
||
208 | 4 | $values[$index], |
|
209 | 4 | false, |
|
210 | 4 | $this->getContextPage() |
|
211 | ); |
||
212 | |||
213 | 4 | if ( $dataValue->isValid() ) { // valid DV: keep |
|
214 | 4 | $containerSemanticData->addPropertyObjectValue( $property, $dataValue->getDataItem() ); |
|
215 | 4 | $sortKeys[] = $dataValue->getDataItem()->getSortKey(); |
|
216 | |||
217 | 4 | $index++; |
|
218 | 4 | $empty = false; |
|
219 | 1 | } elseif ( ( count( $values ) - $index ) == ( count( $this->properties ) - $propertyIndex ) ) { |
|
220 | 1 | $containerSemanticData->addPropertyObjectValue( $property, $dataValue->getDataItem() ); |
|
221 | 1 | $this->addError( $dataValue->getErrors() ); |
|
222 | 1 | ++$index; |
|
223 | } |
||
224 | } |
||
225 | 4 | ++$propertyIndex; |
|
226 | } |
||
227 | |||
228 | 4 | if ( $empty && $this->getErrors() === array() ) { |
|
229 | $this->addErrorMsg( array( 'smw_novalues' ) ); |
||
230 | } |
||
231 | |||
232 | 4 | $this->m_dataitem = new DIContainer( $containerSemanticData ); |
|
233 | |||
234 | // Composite sortkey is to ensure that Store::getPropertyValues can |
||
235 | // apply sorting during value selection |
||
236 | 4 | $this->m_dataitem->addCompositeSortKey( implode( ';', $sortKeys ) ); |
|
237 | 4 | } |
|
238 | |||
239 | /** |
||
240 | * @see DataValue::loadDataItem |
||
241 | */ |
||
242 | 1 | protected function loadDataItem( DataItem $dataItem ) { |
|
243 | |||
244 | 1 | if ( $dataItem->getDIType() === DataItem::TYPE_CONTAINER ) { |
|
245 | $this->m_dataitem = $dataItem; |
||
246 | return true; |
||
247 | 1 | } elseif ( $dataItem->getDIType() === DataItem::TYPE_WIKIPAGE ) { |
|
248 | 1 | $semanticData = new ContainerSemanticData( $dataItem ); |
|
249 | 1 | $semanticData->copyDataFrom( ApplicationFactory::getInstance()->getStore()->getSemanticData( $dataItem ) ); |
|
250 | 1 | $this->m_dataitem = new DIContainer( $semanticData ); |
|
251 | 1 | return true; |
|
252 | } |
||
253 | |||
254 | 1 | return false; |
|
255 | } |
||
256 | |||
257 | 5 | private function findPropertyDataItems( DIProperty $property = null ) { |
|
258 | |||
259 | 5 | if ( $property === null ) { |
|
260 | return array(); |
||
261 | } |
||
262 | |||
263 | 5 | $propertyDiWikiPage = $property->getDiWikiPage(); |
|
264 | |||
265 | 5 | if ( $propertyDiWikiPage === null ) { |
|
266 | return array(); |
||
267 | } |
||
268 | |||
269 | 5 | $listDiProperty = new DIProperty( '_LIST' ); |
|
270 | 5 | $dataItems = ApplicationFactory::getInstance()->getStore()->getPropertyValues( $propertyDiWikiPage, $listDiProperty ); |
|
271 | |||
272 | 5 | if ( count( $dataItems ) == 1 ) { |
|
273 | 5 | $propertyListValue = new PropertyListValue( '__pls' ); |
|
274 | 5 | $propertyListValue->setDataItem( reset( $dataItems ) ); |
|
275 | |||
276 | 5 | if ( $propertyListValue->isValid() ) { |
|
277 | 5 | return $propertyListValue->getPropertyDataItems(); |
|
278 | } |
||
279 | } |
||
280 | |||
281 | return array(); |
||
282 | } |
||
283 | |||
284 | 4 | private function newContainerSemanticData( $value ) { |
|
285 | |||
286 | 4 | if ( $this->m_contextPage === null ) { |
|
287 | 2 | $containerSemanticData = ContainerSemanticData::makeAnonymousContainer(); |
|
288 | 2 | $containerSemanticData->skipAnonymousCheck(); |
|
289 | } else { |
||
290 | 2 | $subobjectName = '_REF' . md5( $value ); |
|
291 | |||
292 | 2 | $subject = new DIWikiPage( |
|
293 | 2 | $this->m_contextPage->getDBkey(), |
|
294 | 2 | $this->m_contextPage->getNamespace(), |
|
295 | 2 | $this->m_contextPage->getInterwiki(), |
|
296 | $subobjectName |
||
297 | ); |
||
298 | |||
299 | 2 | $containerSemanticData = new ContainerSemanticData( $subject ); |
|
300 | } |
||
301 | |||
302 | 4 | return $containerSemanticData; |
|
303 | } |
||
304 | |||
305 | } |
||
306 |