m_typeid = $typeid;
}
/**
* Return a short string that unambiguously specify the type of this
* value. This value will globally be used to identify the type of a
* value (in spite of the class it actually belongs to, which can still
* implement various types).
*/
public function getTypeID() {
return $this->m_typeid;
}
/**
* Set the user value (and compute other representations if possible).
* The given value is a string as supplied by some user. An alternative
* label for printout might also be specified.
*
* @param string $value
* @param mixed $caption
*/
public function setUserValue( $value, $caption = false ) {
$this->m_dataitem = null;
$this->mErrors = []; // clear errors
$this->mHasErrors = false;
$this->m_caption = is_string( $caption ) ? trim( $caption ) : false;
$this->userValue = $value;
// #2435
$value = CharArmor::removeControlChars(
CharArmor::removeSpecialChars( $value )
);
// Process may set a caption if not set yet, depending on datavalue
$this->parseUserValue( $value );
// The following checks for Strip markers generated by MediaWiki to handle special content,
// from parser and extension tags e.g.
,,,.
// See https://en.wikipedia.org/wiki/Help:Strip_markers
// In general, we are not prepared to handle such content properly, and we
// also have no means of obtaining the user input at this point. Hence the assignment
// just fails, even if parseUserValue() above might not have noticed this issue.
// Note: \x07 was used in MediaWiki 1.11.0, \x7f is used now (backwards compatibility, b/c)
if ( is_string( $value ) && ( ( strpos( $value, "\x7f" ) !== false ) || ( strpos( $value, "\x07" ) !== false ) ) ) {
$this->addErrorMsg( [ 'smw-datavalue-stripmarker-parse-error', $value ] );
}
if ( $this->isValid() && !$this->getOption( self::OPT_QUERY_CONTEXT ) ) {
$this->checkAllowedValues();
}
}
/**
* Set the actual data contained in this object. The method returns
* true if this was successful (requiring the type of the dataitem
* to match the data value). If false is returned, the data value is
* left unchanged (the data item was rejected).
*
* @note Even if this function returns true, the data value object
* might become invalid if the content of the data item caused errors
* in spite of it being of the right basic type. False is only returned
* if the data item is fundamentally incompatible with the data value.
*
* @param $dataitem SMWDataItem
* @return boolean
*/
public function setDataItem( SMWDataItem $dataItem ) {
$this->m_dataitem = null;
$this->mErrors = [];
$this->mHasErrors = $this->m_caption = false;
return $this->loadDataItem( $dataItem );
}
/**
* @since 2.5
*
* @param DataValueServiceFactory $dataValueServiceFactory
*/
public function setDataValueServiceFactory( DataValueServiceFactory $dataValueServiceFactory ) {
$this->dataValueServiceFactory = $dataValueServiceFactory;
}
/**
* Specify the property to which this value refers. Property pages are
* used to make settings that affect parsing and display, hence it is
* sometimes needed to know them.
*
* @since 1.6
*
* @param DIProperty $property
*/
public function setProperty( DIProperty $property ) {
$this->m_property = $property;
}
/**
* Returns the property to which this value refers.
*
* @since 1.8
*
* @return DIProperty|null
*/
public function getProperty() {
return $this->m_property;
}
/**
* Specify the wiki page to which this value refers. This information is
* used to parse user values such as "#subsection" which only make sense
* when used on a certain page.
*
* @since 1.7
*
* @param SMWDIWikiPage|null $contextPage
*/
public function setContextPage( SMWDIWikiPage $contextPage = null ) {
$this->m_contextPage = $contextPage;
$this->setOption(
self::OPT_CONTENT_LANGUAGE,
Localizer::getInstance()->getPreferredContentLanguage( $contextPage )->getCode()
);
}
/**
* @since 2.4
*
* @return DIWikiPage|null
*/
public function getContextPage() {
return $this->m_contextPage;
}
/**
* Change the caption (the text used for displaying this datavalue). The given
* value must be a string.
*
* @param string $caption
*/
public function setCaption( $caption ) {
$this->m_caption = $caption;
}
/**
* @since 2.4
*
* @param string $caption
*/
public function getCaption() {
return $this->m_caption;
}
/**
* Returns a preferred caption and may deviate from the standard caption as
* a subclass is permitted to override this method and provide a more
* contextualized display representation (language or value context etc.).
*
* @since 2.4
*
* @return string
*/
public function getPreferredCaption() {
return $this->m_caption;
}
/**
* Define a particular output format. Output formats are user-supplied strings
* that the datavalue may (or may not) use to customise its return value. For
* example, quantities with units of measurement may interpret the string as
* a desired output unit. In other cases, the output format might be built-in
* and subject to internationalisation (which the datavalue has to implement).
* In any case, an empty string resets the output format to the default.
*
* There is one predefined output format that all datavalues should respect: the
* format '-' indicates "plain" output that is most useful for further processing
* the value in a template. It should not use any wiki markup or beautification,
* and it should also avoid localization to the current language. When users
* explicitly specify an empty format string in a query, it is normalized to "-"
* to avoid confusion. Note that empty format strings are not interpreted in
* this way when directly passed to this function.
*
* @param string $formatString
*/
public function setOutputFormat( $formatString ) {
$this->m_outformat = $formatString; // just store it, subclasses may or may not use this
}
/**
* @since 2.4
*
* @return string
*/
public function getOutputFormat() {
return $this->m_outformat;
}
/**
* Add a new error string or array of such strings to the error list.
*
* @note Errors should not be escaped here in any way, in contradiction to what
* the docs used to say here in 1.5 and before. Escaping should happen at the output.
*
* @param mixed $error A single string, or array of strings.
*/
public function addError( $error ) {
if ( is_array( $error ) ) {
$this->mErrors = array_merge( $this->mErrors, $error );
$this->mHasErrors = $this->mHasErrors || ( count( $error ) > 0 );
} else {
$this->mErrors[] = $error;
$this->mHasErrors = true;
}
}
/**
* Messages are not resolved until the output and instead will be kept with the
* message and argument keys (e.g. `[2,"smw_baduri","~*0123*"]`). This allows to
* switch the a representation without requiring language context by the object
* that reports an error.
*
* @since 2.4
*
* @param $parameters
* @param integer|null $type
* @param integer|null $language
*/
public function addErrorMsg( $parameters, $type = null ) {
$this->mErrors[Message::getHash( $parameters, $type )] = Message::encode( $parameters, $type );
$this->mHasErrors = true;
}
/**
* Return a string that displays all error messages as a tooltip, or
* an empty string if no errors happened.
*
* @return string
*/
public function getErrorText() {
return smwfEncodeMessages( $this->mErrors );
}
/**
* Return an array of error messages, or an empty array
* if no errors occurred.
*
* @return array
*/
public function getErrors() {
return $this->mErrors;
}
/**
* @since 3.0
*
* @return array|false
*/
public function getRestrictionError() {
return $this->restrictionError;
}
/**
* @since 2.4
*/
public function clearErrors() {
$this->mErrors = [];
$this->mHasErrors = false;
}
///// Query support /////
/**
* FIXME 3.0, allow NULL as value
*
* @see DataValueDescriptionDeserializer::deserialize
*
* @note Descriptions of values need to know their property to be able to
* create a parsable wikitext version of a query condition again. Thus it
* might be necessary to call setProperty() before using this method.
*
* @param string $value
*
* @return Description
* @throws InvalidArgumentException
*/
public function getQueryDescription( $value ) {
$descriptionDeserializer = DVDescriptionDeserializerRegistry::getInstance()->getDescriptionDeserializerBy( $this );
$description = $descriptionDeserializer->deserialize( $value );
foreach ( $descriptionDeserializer->getErrors() as $error ) {
$this->addError( $error );
}
return $description;
}
/**
* @deprecated since 2.3
*
* @see DescriptionDeserializer::prepareValue
*
* This method should no longer be used for direct public access, instead a
* DataValue is expected to register a DescriptionDeserializer with
* DVDescriptionDeserializerRegistry.
*/
static public function prepareValue( &$value, &$comparator ) {
$comparator = QueryComparator::getInstance()->extractComparatorFromString( $value );
}
///// Get methods /////
/**
* Get the actual data contained in this object or null if the data is
* not defined (due to errors or due to not being set at all).
* @note Most implementations ensure that a data item is always set,
* even if errors occurred, to avoid additional checks for not
* accessing null. Hence, one must not assume that a non-null return
* value here implies that isValid() returns true.
*
* @since 1.6
*
* @return SMWDataItem|SMWDIError
*/
public function getDataItem() {
if ( $this->isValid() ) {
return $this->m_dataitem;
}
return new SMWDIError( $this->mErrors, $this->userValue );
}
/**
* @since 2.2
*
* @return string
*/
public function __toString() {
return $this->getDataItem()->getSerialization();
}
/**
* Returns a short textual representation for this data value. If the value
* was initialised from a user supplied string, then this original string
* should be reflected in this short version (i.e. no normalisation should
* normally happen). There might, however, be additional parts such as code
* for generating tooltips. The output is in wiki text.
*
* The parameter $linked controls linking of values such as titles and should
* be non-NULL and non-false if this is desired.
*/
abstract public function getShortWikiText( $linked = null );
/**
* Returns a short textual representation for this data value. If the value
* was initialised from a user supplied string, then this original string
* should be reflected in this short version (i.e. no normalisation should
* normally happen). There might, however, be additional parts such as code
* for generating tooltips. The output is in HTML text.
*
* The parameter $linker controls linking of values such as titles and should
* be some Linker object (or NULL for no linking).
*/
abstract public function getShortHTMLText( $linker = null );
/**
* Return the long textual description of the value, as printed for
* example in the factbox. If errors occurred, return the error message
* The result always is a wiki-source string.
*
* The parameter $linked controls linking of values such as titles and should
* be non-NULL and non-false if this is desired.
*/
abstract public function getLongWikiText( $linked = null );
/**
* Return the long textual description of the value, as printed for
* example in the factbox. If errors occurred, return the error message
* The result always is an HTML string.
*
* The parameter $linker controls linking of values such as titles and should
* be some Linker object (or NULL for no linking).
*/
abstract public function getLongHTMLText( $linker = null );
/**
* Return the plain wiki version of the value, or
* FALSE if no such version is available. The returned
* string suffices to reobtain the same DataValue
* when passing it as an input string to setUserValue().
*/
abstract public function getWikiValue();
/**
* Returns a short textual representation for this data value. If the value
* was initialised from a user supplied string, then this original string
* should be reflected in this short version (i.e. no normalisation should
* normally happen). There might, however, be additional parts such as code
* for generating tooltips. The output is in the specified format.
*
* The parameter $linker controls linking of values such as titles and should
* be some Linker object (for HTML output), or NULL for no linking.
*/
public function getShortText( $outputformat, $linker = null ) {
switch ( $outputformat ) {
case SMW_OUTPUT_WIKI:
return $this->getShortWikiText( $linker );
case SMW_OUTPUT_HTML:
case SMW_OUTPUT_FILE:
default:
return $this->getShortHTMLText( $linker );
}
}
/**
* Return the long textual description of the value, as printed for
* example in the factbox. If errors occurred, return the error message.
* The output is in the specified format.
*
* The parameter $linker controls linking of values such as titles and should
* be some Linker object (for HTML output), or NULL for no linking.
*/
public function getLongText( $outputformat, $linker = null ) {
switch ( $outputformat ) {
case SMW_OUTPUT_WIKI:
return $this->getLongWikiText( $linker );
case SMW_OUTPUT_HTML:
case SMW_OUTPUT_FILE:
default:
return $this->getLongHTMLText( $linker );
}
}
/**
* Return text serialisation of info links. Ensures more uniform layout
* throughout wiki (Factbox, Property pages, ...).
*
* @param integer $outputformat Element of the SMW_OUTPUT_ enum
* @param $linker
*
* @return string
*/
public function getInfolinkText( $outputformat, $linker = null ) {
if ( $this->getOption( self::OPT_DISABLE_INFOLINKS ) === true ) {
return '';
}
if ( $this->infoLinksProvider === null ) {
$this->infoLinksProvider = $this->dataValueServiceFactory->newInfoLinksProvider( $this );
}
if ( $this->getOption( self::OPT_DISABLE_SERVICELINKS ) === true ) {
$this->infoLinksProvider->disableServiceLinks();
}
$this->infoLinksProvider->setCompactLink(
$this->getOption( self::OPT_COMPACT_INFOLINKS, false )
);
return $this->infoLinksProvider->getInfolinkText( $outputformat, $linker );
}
/**
* Return an array of SMWLink objects that provide additional resources
* for the given value. Captions can contain some HTML markup which is
* admissible for wiki text, but no more. Result might have no entries
* but is always an array.
*/
public function getInfolinks() {
if ( $this->infoLinksProvider === null ) {
$this->infoLinksProvider = $this->dataValueServiceFactory->newInfoLinksProvider( $this );
}
$this->infoLinksProvider->setServiceLinkParameters(
$this->getServiceLinkParams()
);
return $this->infoLinksProvider->createInfoLinks();
}
/**
* Return a string that identifies the value of the object, and that can
* be used to compare different value objects.
* Possibly overwritten by subclasses (e.g. to ensure that returned
* value is normalized first)
*
* @return string
*/
public function getHash() {
return $this->isValid() ? $this->m_dataitem->getHash() : implode( "\t", $this->mErrors );
}
/**
* Convenience method that checks if the value that is used to sort
* data of this type is numeric. This only works if the value is set.
*
* @return boolean
*/
public function isNumeric() {
if ( isset( $this->m_dataitem ) ) {
return is_numeric( $this->m_dataitem->getSortKey() );
} else {
return false;
}
}
/**
* Return true if a value was defined and understood by the given type,
* and false if parsing errors occurred or no value was given.
*
* @return boolean
*/
public function isValid() {
return !$this->mHasErrors && isset( $this->m_dataitem );
}
/**
* Whether a datavalue can be used or not (can be made more restrictive then
* isValid).
*
* @note Validity defines a processable state without any technical restrictions
* while usability is determined by its accessibility to a context
* (permission, convention etc.)
*
* @since 2.2
*
* @return boolean
*/
public function canUse() {
return true;
}
/**
* @since 3.0
*
* @return boolean
*/
public function isRestricted() {
return false;
}
/**
* @since 2.3
*
* @param string $name
* @param array $parameters
*
* @return mixed
* @throws RuntimeException
*/
public function getExtraneousFunctionFor( $name, array $parameters = [] ) {
return $this->dataValueServiceFactory->newExtraneousFunctionByName( $name, $parameters );
}
/**
* @since 3.0
*
* @param string $key
* @param mixed $data
*/
public function setExtensionData( $key, $data ) {
$this->extenstionData[$key] = $data;
}
/**
* @since 3.0
*
* @param string $key
*
* @return mixed
*/
public function getExtensionData( $key ) {
if ( isset( $this->extenstionData[$key] ) ) {
return $this->extenstionData[$key];
}
return null;
}
/**
* @since 2.4
*
* @return Options|null $options
*/
public function copyOptions( Options $options = null ) {
if ( $options === null ) {
return;
}
foreach ( $options->getOptions() as $key => $value ) {
$this->setOption( $key, $value );
}
}
/**
* @since 2.4
*
* @return string $key
* @param mxied $value
*/
public function setOption( $key, $value ) {
if ( $this->options === null ) {
$this->options = new Options();
}
$this->options->set( $key, $value );
}
/**
* @since 2.4
*
* @param string $key
*
* @return mixed|false
*/
public function getOption( $key, $default = false ) {
if ( $this->options !== null && $this->options->has( $key ) ) {
return $this->options->get( $key );
}
return $default;
}
/**
* @since 3.0
*
* @param integer $feature
*
* @return boolean
*/
public function hasFeature( $feature ) {
if ( $this->options !== null ) {
return $this->options->isFlagSet( 'smwgDVFeatures', (int)$feature );
}
return false;
}
/**
* @deprecated since 3.0, use DataValue::hasFeature
* @since 2.4
*/
public function isEnabledFeature( $feature ) {
return $this->hasFeature( $feature );
}
/**
* @since 2.5
*
* @return Options
*/
protected function getOptions() {
return $this->options;
}
/**
* Initialise the datavalue from the given value string.
* The format of this strings might be any acceptable user input
* and especially includes the output of getWikiValue().
*
* @param string $value
*/
abstract protected function parseUserValue( $value );
/**
* Set the actual data contained in this object. The method returns
* true if this was successful (requiring the type of the dataitem
* to match the data value). If false is returned, the data value is
* left unchanged (the data item was rejected).
*
* @note Even if this function returns true, the data value object
* might become invalid if the content of the data item caused errors
* in spite of it being of the right basic type. False is only returned
* if the data item is fundamentally incompatible with the data value.
*
* @since 1.6
*
* @param SMWDataItem $dataItem
*
* @return boolean
*/
abstract protected function loadDataItem( SMWDataItem $dataItem );
/**
* Overwritten by callers to supply an array of parameters that can be used for
* creating servicelinks. The number and content of values in the parameter array
* may vary, depending on the concrete datatype.
*/
protected function getServiceLinkParams() {
return false;
}
/**
* Check if property is range restricted and, if so, whether the current value is allowed.
* Creates an error if the value is illegal.
*/
protected function checkAllowedValues() {
if ( $this->dataValueServiceFactory === null ) {
return;
}
$this->dataValueServiceFactory->getConstraintValueValidator()->validate( $this );
}
}