summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/SemanticMediaWiki/src/DataValues/ValueValidators/UniquenessConstraintValueValidator.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/src/DataValues/ValueValidators/UniquenessConstraintValueValidator.php')
-rw-r--r--www/wiki/extensions/SemanticMediaWiki/src/DataValues/ValueValidators/UniquenessConstraintValueValidator.php205
1 files changed, 205 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/src/DataValues/ValueValidators/UniquenessConstraintValueValidator.php b/www/wiki/extensions/SemanticMediaWiki/src/DataValues/ValueValidators/UniquenessConstraintValueValidator.php
new file mode 100644
index 00000000..65ace8e3
--- /dev/null
+++ b/www/wiki/extensions/SemanticMediaWiki/src/DataValues/ValueValidators/UniquenessConstraintValueValidator.php
@@ -0,0 +1,205 @@
+<?php
+
+namespace SMW\DataValues\ValueValidators;
+
+use SMW\PropertySpecificationLookup;
+use SMW\DIWikiPage;
+use SMWDataValue as DataValue;
+use SMW\RequestOptions;
+use SMW\Store;
+
+/**
+ * @private
+ *
+ * Only allow values that are unique where uniqueness is establised for the first (
+ * in terms of time which also entails that after a full rebuild the first value
+ * found is being categorised as established value) value assigned to a property
+ * (that requires this trait) and any value that compares to an establised
+ * value with the same literal representation is being identified as violating the
+ * uniqueness constraint.
+ *
+ * @license GNU GPL v2+
+ * @since 2.4
+ *
+ * @author mwjames
+ */
+class UniquenessConstraintValueValidator implements ConstraintValueValidator {
+
+ /**
+ * @var Store
+ */
+ private $store;
+
+ /**
+ * @var PropertySpecificationLookup
+ */
+ private $propertySpecificationLookup;
+
+ /**
+ * @var boolean
+ */
+ private $hasConstraintViolation = false;
+
+ /**
+ * Tracks annotations for the current context to verify that a subject only
+ * contains unique assignments.
+ *
+ * @var array
+ */
+ private static $annotations = [];
+
+ /**
+ * @since 2.4
+ *
+ * @param Store $store
+ * @param PropertySpecificationLookup $propertySpecificationLookup
+ */
+ public function __construct( Store $store, PropertySpecificationLookup $propertySpecificationLookup ) {
+ $this->store = $store;
+ $this->propertySpecificationLookup = $propertySpecificationLookup;
+ }
+
+ /**
+ * @since 2.4
+ *
+ * {@inheritDoc}
+ */
+ public function hasConstraintViolation() {
+ return $this->hasConstraintViolation;
+ }
+
+ /**
+ * @since 3.0
+ *
+ * {@inheritDoc}
+ */
+ public function clear() {
+ self::$annotations = [];
+ }
+
+ /**
+ * @since 2.4
+ *
+ * {@inheritDoc}
+ */
+ public function validate( $dataValue ) {
+
+ $this->hasConstraintViolation = false;
+
+ if ( !$this->canValidate( $dataValue ) ) {
+ return $this->hasConstraintViolation;
+ }
+
+ $property = $dataValue->getProperty();
+
+ if ( !$this->propertySpecificationLookup->hasUniquenessConstraint( $property ) ) {
+ return $this->hasConstraintViolation;
+ }
+
+ $contextPage = $dataValue->getContextPage();
+
+ // Exclude the current page from the result match to check whether another
+ // page matches the condition and if so then the value can no longer be
+ // assigned and is not unique
+ $requestOptions = new RequestOptions();
+
+ $requestOptions->addExtraCondition( function( $store, $query, $alias ) use( $contextPage ) {
+ return $query->neq( "$alias.s_id", $store->getObjectIds()->getId( $contextPage ) );
+ }
+ );
+
+ $requestOptions->setLimit( 2 );
+ $count = 0;
+
+ if ( !$this->hasAnnotation( $dataValue ) ) {
+ $entityValueUniquenessConstraintChecker = $this->store->service( 'EntityValueUniquenessConstraintChecker' );
+
+ $res = $entityValueUniquenessConstraintChecker->checkConstraint(
+ $property,
+ $dataValue->getDataItem(),
+ $requestOptions
+ );
+
+ $count = count( $res );
+ }
+
+ // Check whether the current page has any other annotation for the
+ // same property
+ if ( $count < 1 && $this->isRegistered( $dataValue ) ) {
+ $dataValue->addErrorMsg(
+ [
+ 'smw-datavalue-uniqueness-constraint-isknown',
+ $property->getLabel(),
+ $contextPage->getTitle()->getPrefixedText(),
+ $dataValue->getWikiValue()
+ ]
+ );
+
+ $this->hasConstraintViolation = true;
+ }
+
+ // Has the page different values for the same property?
+ if ( $count < 1 ) {
+ return $this->hasConstraintViolation;
+ }
+
+ $this->hasConstraintViolation = true;
+
+ foreach ( $res as $dataItem ) {
+ $val = $dataValue->isValid() ? $dataValue->getWikiValue() : '...';
+ $text = '';
+
+ if ( $dataItem !== null && ( $title = $dataItem->getTitle() ) !== null ) {
+ $text = $title->getPrefixedText();
+ }
+
+ $dataValue->addErrorMsg(
+ [
+ 'smw-datavalue-uniqueness-constraint-error',
+ $property->getLabel(),
+ $val,
+ $text
+ ]
+ );
+ }
+
+ return $this->hasConstraintViolation;
+ }
+
+ private function canValidate( $dataValue ) {
+
+ if ( !$dataValue->isEnabledFeature( SMW_DV_PVUC ) || !$dataValue instanceof DataValue ) {
+ return false;
+ }
+
+ return $dataValue->getContextPage() !== null && $dataValue->getProperty() !== null;
+ }
+
+ private function isRegistered( $dataValue ) {
+
+ $contextPage = $dataValue->getContextPage();
+ $dataItem = $dataValue->getDataItem();
+ $property = $dataValue->getProperty();
+
+ $valueHash = md5( $property->getKey() . $dataItem->getHash() );
+ $key = $property->getKey();
+ $hash = $contextPage->getHash();
+
+ if ( isset( self::$annotations[$hash][$key] ) && self::$annotations[$hash][$key] !== $valueHash ) {
+ return true;
+ } else {
+ self::$annotations[$hash][$key] = $valueHash;
+ }
+
+ return false;
+ }
+
+ private function hasAnnotation( $dataValue ) {
+
+ $key = $dataValue->getProperty()->getKey();
+ $hash = $dataValue->getContextPage()->getHash();
+
+ return isset( self::$annotations[$hash][$key] );
+ }
+
+}