Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 31
CRAP
0.00% covered (danger)
0.00%
0 / 187
PFTemplateField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 31
9120
0.00% covered (danger)
0.00%
0 / 187
 create
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 11
 toWikitext
0.00% covered (danger)
0.00%
0 / 1
210
0.00% covered (danger)
0.00%
0 / 26
 newFromParams
0.00% covered (danger)
0.00%
0 / 1
156
0.00% covered (danger)
0.00%
0 / 22
 setTypeAndPossibleValues
0.00% covered (danger)
0.00%
0 / 1
72
0.00% covered (danger)
0.00%
0 / 26
 setSemanticProperty
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 4
 setCargoFieldData
0.00% covered (danger)
0.00%
0 / 1
110
0.00% covered (danger)
0.00%
0 / 29
 getFieldName
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getValueLabels
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getLabel
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getSemanticProperty
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getPropertyType
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getExpectedCargoField
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 getFullCargoField
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 3
 getFieldType
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getRealFieldType
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getPossibleValues
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 getHierarchyStructure
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 isList
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getDelimiter
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getDisplay
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getNamespace
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 isMandatory
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 isUnique
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getRegex
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getHoldsTemplate
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 setLabel
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 setNamespace
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 setFieldType
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 4
 setPossibleValues
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 setHierarchyStructure
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 createText
0.00% covered (danger)
0.00%
0 / 1
306
0.00% covered (danger)
0.00%
0 / 32
<?php
/**
 * Defines a class, PFTemplateField, that represents a field in a template,
 * including any possible Cargo or SMW storage it may have. Used in both
 * creating templates and displaying user-created forms.
 *
 * @author Yaron Koren
 * @file
 * @ingroup PF
 */
class PFTemplateField {
    private $mFieldName;
    private $mValueLabels;
    private $mLabel;
    /**
     * SMW-specific fields
     */
    private $mSemanticProperty;
    private $mPropertyType;
    /**
     * Cargo-specific fields
     */
    private $mCargoTable;
    private $mCargoField;
    private $mFieldType;
    private $mRealFieldType = null;
    private $mHierarchyStructure;
    private $mPossibleValues;
    private $mIsList;
    private $mDelimiter;
    private $mDisplay;
    private $mNamespace;
    private $mIsMandatory = false;
    private $mIsUnique = false;
    private $mRegex = null;
    private $mHoldsTemplate = null;
    static function create( $name, $label, $semanticProperty = null, $isList = null, $delimiter = null, $display = null ) {
        $f = new PFTemplateField();
        $f->mFieldName = trim( str_replace( '\\', '', $name ) );
        if ( $label !== null ) {
            // Keep this field null if no value was set.
            $f->mLabel = trim( str_replace( '\\', '', $label ) );
        }
        $f->setSemanticProperty( $semanticProperty );
        $f->mIsList = $isList;
        $f->mDelimiter = $delimiter;
        $f->mDisplay = $display;
        // Delimiter should default to ','.
        if ( $isList && !$delimiter ) {
            $f->mDelimiter = ',';
        }
        return $f;
    }
    public function toWikitext() {
        $attribsStrings = [];
        // Only include the label if it's different from the field name.
        if ( $this->mLabel != '' &&
            ( $this->mLabel !== $this->mFieldName ) ) {
            $attribsStrings['label'] = $this->mLabel;
        }
        if ( $this->mCargoField != '' && $this->mCargoField !== str_replace( ' ', '_', $this->mFieldName ) ) {
            $attribsStrings['cargo field'] = $this->mCargoField;
        }
        // Only set list and delimiter information if there's no Cargo
        // field - if there is, they will be set in #cargo_declare.
        if ( $this->mCargoField == '' ) {
            if ( $this->mIsList == true ) {
                $attribsStrings['list'] = true;
                if ( $this->mDelimiter != ',' ) {
                    $attribsStrings['delimiter'] = $this->mDelimiter;
                }
            }
        }
        if ( $this->mSemanticProperty != '' ) {
            $attribsStrings['property'] = $this->mSemanticProperty;
        }
        if ( $this->mNamespace != '' ) {
            $attribsStrings['namespace'] = $this->mNamespace;
        }
        if ( $this->mDisplay != '' ) {
            $attribsStrings['display'] = $this->mDisplay;
        }
        $text = $this->mFieldName;
        if ( count( $attribsStrings ) > 0 ) {
            $attribsFullStrings = [];
            foreach ( $attribsStrings as $key => $value ) {
                if ( $value === true ) {
                    $attribsFullStrings[] = $key;
                } else {
                    $attribsFullStrings[] = "$key=$value";
                }
            }
            $text .= ' (' . implode( ';', $attribsFullStrings ) . ')';
        }
        return $text;
    }
    static function newFromParams( $fieldName, $fieldParams ) {
        $f = new PFTemplateField();
        $f->mFieldName = $fieldName;
        foreach ( $fieldParams as $key => $value ) {
            if ( $key == 'label' ) {
                $f->mLabel = $value;
            } elseif ( $key == 'cargo field' ) {
                $f->mCargoField = $value;
            } elseif ( $key == 'property' ) {
                $f->setSemanticProperty( $value );
            } elseif ( $key == 'list' ) {
                $f->mIsList = true;
            } elseif ( $key == 'delimiter' ) {
                $f->mDelimiter = $value;
            } elseif ( $key == 'namespace' ) {
                $f->mNamespace = $value;
            } elseif ( $key == 'display' ) {
                $f->mDisplay = $value;
            } elseif ( $key == 'holds template' ) {
                $f->mHoldsTemplate = $value;
            }
        }
        // Delimiter should default to ','.
        if ( $f->mIsList && !$f->mDelimiter ) {
            $f->mDelimiter = ',';
        }
        return $f;
    }
    function setTypeAndPossibleValues() {
        if ( !defined( 'SMW_NS_PROPERTY' ) ) {
            return;
        }
        // The presence of "-" at the beginning of a property name
        // (which happens if PF tries to parse an inverse query)
        // leads to an error in SMW - just exit if that's the case.
        if ( strpos( $this->mSemanticProperty, '-' ) === 0 ) {
            return;
        }
        $proptitle = Title::makeTitleSafe( SMW_NS_PROPERTY, $this->mSemanticProperty );
        if ( $proptitle === null ) {
            return;
        }
        $store = PFUtils::getSMWStore();
        // this returns an array of objects
        $allowed_values = PFValuesUtils::getSMWPropertyValues( $store, $proptitle, "Allows value" );
        if ( empty( $allowed_values ) ) {
            $allowed_values = PFValuesUtils::getSMWPropertyValues( $store, $proptitle, "Allows value list" );
        }
        $label_formats = PFValuesUtils::getSMWPropertyValues( $store, $proptitle, "Has field label format" );
        $propValue = SMWDIProperty::newFromUserLabel( $this->mSemanticProperty );
        $this->mPropertyType = $propValue->findPropertyTypeID();
        foreach ( $allowed_values as $allowed_value ) {
            // HTML-unencode each value
            $wiki_value = html_entity_decode( $allowed_value );
            $this->mPossibleValues[] = $wiki_value;
            if ( count( $label_formats ) > 0 ) {
                $label_format = $label_formats[0];
                $prop_instance = SMWDataValueFactory::findTypeID( $this->mPropertyType );
                $label_value = SMWDataValueFactory::newTypeIDValue( $prop_instance, $wiki_value );
                $label_value->setOutputFormat( $label_format );
                $this->mValueLabels[$wiki_value] = html_entity_decode( $label_value->getWikiValue() );
            }
        }
        // HACK - if there were any possible values, set the property
        // type to be 'enumeration', regardless of what the actual type is
        if ( count( $this->mPossibleValues ) > 0 ) {
            $this->mPropertyType = 'enumeration';
        }
    }
    /**
     * Called if a matching property is found for a template field when
     * a template is parsed during the creation of a form.
     * @param string $semantic_property
     */
    function setSemanticProperty( $semantic_property ) {
        $this->mSemanticProperty = str_replace( '\\', '', $semantic_property );
        $this->mPossibleValues = [];
        // set field type and possible values, if any
        $this->setTypeAndPossibleValues();
    }
    /**
     * Equivalent to setSemanticProperty(), but called when using Cargo
     * instead of SMW.
     * @param string $tableName
     * @param string $fieldName
     * @param CargoFieldDescription|null $fieldDescription
     */
    function setCargoFieldData( $tableName, $fieldName, $fieldDescription = null ) {
        $this->mCargoTable = $tableName;
        $this->mCargoField = $fieldName;
        if ( $fieldDescription === null ) {
            try {
                $tableSchemas = CargoUtils::getTableSchemas( [ $tableName ] );
            } catch ( MWException $e ) {
                return;
            }
            if ( count( $tableSchemas ) == 0 ) {
                return;
            }
            $tableSchema = $tableSchemas[$tableName];
            $fieldDescriptions = $tableSchema->mFieldDescriptions;
            if ( array_key_exists( $fieldName, $fieldDescriptions ) ) {
                $fieldDescription = $fieldDescriptions[$fieldName];
            } else {
                return;
            }
        }
        // We have some "pseudo-types", used for setting the correct
        // form input.
        if ( $fieldDescription->mAllowedValues != null ) {
            if ( $fieldDescription->mIsHierarchy == true ) {
                $this->mFieldType = 'Hierarchy';
                $this->mHierarchyStructure = $fieldDescription->mHierarchyStructure;
            } else {
                $this->mFieldType = 'Enumeration';
            }
            $this->mRealFieldType = $fieldDescription->mType;
        } elseif ( $fieldDescription->mType == 'Text' && $fieldDescription->mSize != '' && $fieldDescription->mSize <= 100 ) {
            $this->mFieldType = 'String';
        } else {
            $this->mFieldType = $fieldDescription->mType;
        }
        $this->mIsList = $fieldDescription->mIsList;
        $this->mDelimiter = $fieldDescription->getDelimiter();
        $this->mPossibleValues = $fieldDescription->mAllowedValues;
        $this->mIsMandatory = $fieldDescription->mIsMandatory;
        $this->mIsUnique = $fieldDescription->mIsUnique;
        $this->mRegex = $fieldDescription->mRegex;
    }
    function getFieldName() {
        return $this->mFieldName;
    }
    function getValueLabels() {
        return $this->mValueLabels;
    }
    function getLabel() {
        return $this->mLabel;
    }
    function getSemanticProperty() {
        return $this->mSemanticProperty;
    }
    function getPropertyType() {
        return $this->mPropertyType;
    }
    function getExpectedCargoField() {
        if ( $this->mCargoField != '' ) {
            return $this->mCargoField;
        } else {
            return str_replace( ' ', '_', $this->mFieldName );
        }
    }
    function getFullCargoField() {
        if ( $this->mCargoTable == '' || $this->mCargoField == '' ) {
            return null;
        }
        return $this->mCargoTable . '|' . $this->mCargoField;
    }
    function getFieldType() {
        return $this->mFieldType;
    }
    function getRealFieldType() {
        return $this->mRealFieldType;
    }
    function getPossibleValues() {
        if ( $this->mPossibleValues == null ) {
            return [];
        }
        return $this->mPossibleValues;
    }
    function getHierarchyStructure() {
        return $this->mHierarchyStructure;
    }
    function isList() {
        return $this->mIsList;
    }
    function getDelimiter() {
        return $this->mDelimiter;
    }
    function getDisplay() {
        return $this->mDisplay;
    }
    function getNamespace() {
        return $this->mNamespace;
    }
    function isMandatory() {
        return $this->mIsMandatory;
    }
    function isUnique() {
        return $this->mIsUnique;
    }
    function getRegex() {
        return $this->mRegex;
    }
    function getHoldsTemplate() {
        return $this->mHoldsTemplate;
    }
    function setLabel( $label ) {
        $this->mLabel = $label;
    }
    function setNamespace( $namespace ) {
        $this->mNamespace = $namespace;
    }
    function setFieldType( $fieldType ) {
        $this->mFieldType = $fieldType;
        if ( $fieldType == 'File' ) {
            $this->mNamespace = PFUtils::getCanonicalName( NS_FILE );
        }
    }
    function setPossibleValues( $possibleValues ) {
        $this->mPossibleValues = $possibleValues;
    }
    function setHierarchyStructure( $hierarchyStructure ) {
        $this->mHierarchyStructure = $hierarchyStructure;
    }
    function createText( $cargoInUse ) {
        $fieldProperty = $this->mSemanticProperty;
        // If this field is meant to contain a list, and the field has
        // an associated SMW property, add on an 'arraymap' function,
        // which will call the property tag on every element in the
        // list. If, on the other hand, it uses Cargo, use #arraymap
        // just for the link - but only if it's of type "Page".
        if ( $this->mIsList && ( $fieldProperty != '' ||
            ( $cargoInUse && $this->mFieldType == 'Page' ) ) ) {
            // Find a string that's not in the property
            // name, to be used as the variable.
            // Default is "x" - also use this if all the attempts fail.
            $var = "x";
            if ( strstr( $fieldProperty, $var ) ) {
                $var_options = [ 'y', 'z', 'xx', 'yy', 'zz', 'aa', 'bb', 'cc' ];
                foreach ( $var_options as $option ) {
                    if ( !strstr( $fieldProperty, $option ) ) {
                        $var = $option;
                        break;
                    }
                }
            }
            $text = "{{#arraymap:{{{" . $this->mFieldName . '|}}}|' . $this->mDelimiter . "|$var|[[";
            if ( $fieldProperty == '' ) {
                $text .= "$var]]";
            } elseif ( $this->mNamespace == '' ) {
                $text .= "$fieldProperty::$var]]";
            } else {
                $text .= $this->mNamespace . ":$var]] {{#set:" . $fieldProperty . "=$var}} ";
            }
            // Close #arraymap call.
            $text .= "}}\n";
            return $text;
        }
        // Not a list.
        $fieldParam = '{{{' . $this->mFieldName . '|}}}';
        if ( $this->mNamespace === null ) {
            $fieldString = $fieldParam;
        } else {
            $fieldString = $this->mNamespace . ':' . $fieldParam;
        }
        if ( $fieldProperty == '' ) {
            if ( $cargoInUse && ( $this->mFieldType == 'Page' || $this->mFieldType == 'File' ) ) {
                $fieldString = "[[$fieldString]]";
                // Add an #if around the link, to prevent
                // anything from getting displayed on the
                // screen for blank values, if the
                // ParserFunctions extension is installed.
                if ( ExtensionRegistry::getInstance()->isLoaded( 'ParserFunctions' ) ) {
                    $fieldString = "{{#if:$fieldParam|$fieldString}}";
                }
                return $fieldString;
            }
            return $fieldString;
        } elseif ( $this->mNamespace === null ) {
            return "[[$fieldProperty::$fieldString]]";
        } else {
            // Special handling is needed, for at
            // least the File and Category namespaces.
            return "[[$fieldString]] {{#set:$fieldProperty=$fieldString}}";
        }
    }
}