Check the qname expression (if there is one)
{@inheritDoc}
@see \XBRL\Formulas\Resources\Resource::validate()
@param VariableSet $variableSet
@param XmlNamespaceManager $nsMgr
336560
public function validate( $variableSet, $nsMgr )
	{
		if ( $this->qnameExpressions )
		{
			foreach ( $this->qnameExpressions as $qnameExpression )
			{
				try
				{
					$xpath2Expression = XPath2Expression::Compile( $qnameExpression, $nsMgr );
					if ( parent::checkForCoverXFIFunctionUse( $qnameExpression, $xpath2Expression ) )
					{
						return false;
					}
					$this->qnameXPath2Expressions[] = $xpath2Expression;
				}
				catch ( \Exception $ex )
				{
					\XBRL_Log::getInstance()->formula_validation( "Concept name filter", "Failed to compile qname expression",
						array(
							'qname expression' => $qnameExpression,
							'error' => $ex instanceof XPath2Exception ? $ex->ErrorCode : get_class( $ex ),
							'reason' => $ex->getMessage()
						)
					);
					return false;
				}
			}
		}

		return true;
	}
555548
public function validate( $variableSet, $nsMgr )
	{
		try
		{
			if ( $this->scheme )
			{
				if ( ! $this->schemaXPath2Expression )
				{
					$this->schemaXPath2Expression = XPath2Expression::Compile( $this->scheme, $nsMgr );
				}
			}
		}
		catch ( \Exception $ex )
		{
			\XBRL_Log::getInstance()->formula_validation( "Specific identifier filter", "Failed to compile scheme expression",
				array(
					'schema expression' => $this->scheme,
					'error' => $ex instanceof XPath2Exception ? $ex->ErrorCode : get_class( $ex ),
					'reason' => $ex->getMessage()
				)
			);
			return false;
		}

		try
		{
			if ( $this->value )
			{
				if ( ! $this->valueXPath2Expression )
				{
					$this->valueXPath2Expression = XPath2Expression::Compile( $this->value, $nsMgr );
				}
			}
		}
		catch ( \Exception $ex )
		{
			\XBRL_Log::getInstance()->formula_validation( "Specific identifier filter", "Failed to compile scheme expression",
				array(
					'schema expression' => $this->scheme,
					'error' => $ex instanceof XPath2Exception ? $ex->ErrorCode : get_class( $ex ),
					'reason' => $ex->getMessage()
				)
			);
			return false;
		}

		return true;
	}
1080149
public static function validateClass($name, $namespace = null)
    {
        $name = self::validateNamingConvention($name);

        $prefix = !empty($namespace) ? $namespace . '\\' : '';

        $name = self::validateUnique($name, function ($name) use ($prefix) {
                // Use reflection to get access to private isKeyword method.
                // @todo Remove this when we stop supporting PHP 5.3.
                $isKeywordMethod = new \ReflectionMethod(__CLASS__, 'isKeyword');
                $isKeywordMethod->setAccessible(true);
                $isKeyword = $isKeywordMethod->invoke(null, $name);
             return !$isKeyword &&
                !interface_exists($prefix . $name) &&
                !class_exists($prefix . $name);
        }, self::NAME_SUFFIX);

        return $name;
    }
669963
public static function GetNamespaceUriForPrefix( $context, $prefix, $nav )
	{
		$ns  = "";
		if ( $prefix instanceof  Undefined || $prefix . "" == "" )
		{
			$ns = $nav->getNamespaceURI();
		}
		else
		{
			/**
			 * @var XmlNamespaceManager $nsmgr
			 */
		    $nsmgr = new XmlNamespaceManager();
		    ExtFuncs::ScanLocalNamespaces( $nsmgr, $nav->CloneInstance(), false );
		    $ns = $nsmgr->lookupNamespace( $prefix . "" );
		}
		return is_null( $ns )
			? Undefined::getValue()
			: new AnyUriValue( $ns );
	}
860760
public function toQuery( $variableSet, $factVariableBinding )
	{
		$clauses = array();

		$dimensionClause = "";
		if ( $this->dimension )
		{
			// $qname = qname( $this->dimension );
			$dimensionClause = "fn:QName('{$this->dimension['namespace']}','{$this->dimension['name']}')";
		}
		else if ( $this->dimensionExpression )
		{
			$dimensionClause = $this->dimensionExpression;
		}
		else
		{
			return "false()";
		}

		if ( ! $this->members )
		{
			return "xfi:fact-has-explicit-dimension(.,$dimensionClause)";
		}

		foreach ( $this->members as $member )
		{
			$memberClause = "";
			if ( isset( $member['qname'] ) )
			{
				// $qname = qname( $member['qname'] );
				$memberClause = "fn:QName('{$member['qname']['namespace']}','{$member['qname']['name']}')";
			}
			else if ( isset( $member['qnameExpression'] ) )
			{
				$memberClause = $member['qnameExpression'];
			}
			elseif ( isset( $member['variable'] ) )
			{
				// $memberClause = "fn:QName('{$member['variable']['namespace']}','{$member['variable']['name']}')";
				// TODO Can the QName resulting from this query be determined once for this set of aspect facts?
				//      If the implied variable can depend on other variables that are linked to the current fact
				//      then the QName cannot be determined upfront.  However it formula rule prohibit such a
				//      relationship then it can.
				//      For now assume the worst case and have the clause evaluated for every fact
				$variable = $member['variable']['originalPrefix']
					? "\${$member['variable']['originalPrefix']}:{$member['variable']['name']}"
					: "\${$member['variable']['name']}";

				// $variable is 'the current fact'
				$memberClause = "xfi:fact-explicit-dimension-value( $variable, $dimensionClause )";
			}
			else
			{
				continue;
			}

			// Dimensions filter spec 2.1 states:
			// If a filter member does not contain a filter-member linkrole, arcrole and axis, then the only
			// domain member in its filter-member set is the domain member identified by the filter-member value.
			if ( ! isset( $member['arcrole'] ) || ! isset( $member['axis'] ) || ! isset( $member['linkrole'] ) )
			{
				if ( isset( $member['axis'] ) && in_array( $member['axis'], array( 'DRS-child', 'DRS-descendant' ) ) )
				{
					$axis = isset( $member['axis'] ) ? $member['axis'] : "";
					$linkrole = isset( $member['linkrole'] ) ? $member['linkrole'] : "";
					$xpath = "( if (xfi:fact-has-explicit-dimension(.,$dimensionClause)) then " .
							 "( some \$member in xfi:filter-member-DRS-selection($dimensionClause,fn:node-name(.),$memberClause,'$linkrole','$axis') satisfies (xfi:fact-explicit-dimension-value(.,$dimensionClause) eq \$member) )" .
							 " else fn:false() )";
					$clauses[] = $xpath;
				}
				else
				{
					$clauses[] = "xfi:fact-has-explicit-dimension-value(.,$dimensionClause,$memberClause)";
				}
			}
			else
			{
				$arcrole = isset( $member['arcrole'] ) ? $member['arcrole'] : "";
				$axis = isset( $member['axis'] ) ? $member['axis'] : "";
				$linkrole = isset( $member['linkrole'] ) ? $member['linkrole'] : "";

				// TODO This needs optimizing otherwise the whole expression is evaluated for every fact element.
				$xpath = "( if (xfi:fact-has-explicit-dimension(.,$dimensionClause)) then " .
						 "( some \$member in xfi:filter-member-network-selection($dimensionClause,$memberClause,'$linkrole','$arcrole','$axis') satisfies (xfi:fact-explicit-dimension-value(.,$dimensionClause) eq \$member) )" .
						 " else fn:false() )";
				$clauses[] = $xpath;
			}
		}

		return implode( " or ", $clauses );

	}
636201
public function toQuery( $variableSet, $factVariableBinding )
	{
		$test = $this->test ? $this->test : 'true()';
		// $filter = "(if (fn:QName('http://www.xbrl.org/2003/instance','tuple') = xfi:concept-substitutions(fn:node-name(.))) then (false()) else (xfi:period(.)[$test]))";
		$filter = "(xfi:period(.)[$test])";
		return $filter;
	}
739694
public function validate( $variableSet, $nsMgr )
	{
		$log = \XBRL_Log::getInstance();

		try
		{
			if ( isset( $this->value ) && ! empty( $this->value ) )
			{
				$expression = XPath2Expression::Compile( $this->value, $nsMgr );
				$this->valueXPath2expression = $expression;

				if ( ! $this->source && ! $this->unitRule )
				{
					$qnames = $expression->getParameterQNames();
					$vars = array();
					foreach( $qnames as $qname )
					{
						$vars[ $qname->clarkNotation() ] = 1;
					}
					$resultType = $expression->GetResultType( $vars );

					// If the result is number then there MUST be a unit rule
					if ( $resultType == XPath2ResultType::Number )
					{
						$log->formula_validation( "Formula", "A formula with a numeric result MUST have a unit rule",
							array(
								'error' => 'xbrlfe:missingUnitRule'
							)
						);
					}
				}
			}
		}
		catch ( XPath2Exception $ex )
		{
			// BMS 2018-03-27 Test 21201 V-01 requires that this compile failure return xbrlve:noCustomFunctionSignature
			//				  because the custom function my-own:ending-balance does not exist
			$log->formula_validation( "Formula", "Failed to compile value expression",
				array(
					'formula' => $this->label,
					'value' => $this->value,
					'error' => $ex->ErrorCode == 'XPST0017' ? "xbrlve:noCustomFunctionSignature" : $ex->ErrorCode,
					'reason' => $ex->getMessage()
				)
			);

			return false;

		}
		catch ( FormulasException $ex )
		{
			throw $ex;
		}
		catch ( \Exception $ex )
		{
			// BMS 2018-03-27 Test 21201 V-01 requires that this compile failure return xbrlve:noCustomFunctionSignature
			//				  becauase the custom function my-own:ending-balance does not exist
			$log->formula_validation( "Formula", "Failed to compile value expression",
				array(
					'formula' => $this->label,
					'value' => $this->value,
					'error' => $ex instanceof XPath2Exception ? ( $ex->ErrorCode == 'XPST0017' ? "err:XPST0017" : $ex->ErrorCode ) : get_class( $ex ),
					'reason' => $ex->getMessage()
				)
			);

			return false;
		}

		if ( $this->tupleLocationRule )
		{
			// The name given in the rule MUST be one of the scope dependency indexes
			if ( ! isset( $this->scopeDependencies[ $this->tupleLocationRule ] ) )
			{
				// Not valid so remove the rule
				$log->warning( "The tuple loctation rule ({$this->tupleLocationRule}) on formula '{$this->label}' does not match the name on a variable scope arc so will be ignored." );
				$this->tupleLocationRule = null;
			}

		}

		if ( $this->decimalsRule && ! is_numeric( $this->precisionRule ) )
		{
			try
			{
				$xpath2Expression = XPath2Expression::Compile( $this->decimalsRule, $nsMgr );
			}
			catch ( XPath2Exception $ex )
			{
				\XBRL_Log::getInstance()->formula_validation( "Formula decimal value", "Failed to compile expression",
					array(
						'qname expression' => $this->decimalsRule,
						'error' => $ex instanceof XPath2Exception ? ( $ex->ErrorCode == 'XPST0017' ? "xbrlve:noCustomFunctionSignature" : $ex->ErrorCode ) : get_class( $ex ),
						'reason' => $ex->getMessage()
					)
				);
			}
			catch ( \Exception $ex )
			{
				// BMS 2018-03-27 Test 21201 V-02 requires that this compile failure return xbrlve:noCustomFunctionSignature
				//				  becauase the custom function my-own:ending-balance does not exist
				\XBRL_Log::getInstance()->formula_validation( "Formula decimal value", "Failed to compile expression",
					array(
						'qname expression' => $this->decimalsRule,
						'error' => $ex instanceof XPath2Exception ? ( $ex->ErrorCode == 'XPST0017' ? "err:XPST0017" : $ex->ErrorCode ) : get_class( $ex ),
						'reason' => $ex->getMessage()
					)
				);
			}
		}

		if ( $this->precisionRule && ! is_numeric( $this->precisionRule ) )
		{
			try
			{
				$xpath2Expression = XPath2Expression::Compile( $this->precisionRule, $nsMgr );
			}
			catch ( XPath2Exception $ex )
			{
				\XBRL_Log::getInstance()->formula_validation( "Formula precision value", "Failed to compile expression",
					array(
						'qname expression' => $this->precisionRule,
						'error' => $ex instanceof XPath2Exception ? ( $ex->ErrorCode == 'XPST0017' ? "xbrlve:noCustomFunctionSignature" : $ex->ErrorCode ) : get_class( $ex ),
						'reason' => $ex->getMessage()
					)
				);
			}
			catch ( \Exception $ex )
			{
				// BMS 2018-03-27 Test 21201 V-01 requires that this compile failure return xbrlve:noCustomFunctionSignature
				//				  becauase the custom function my-own:ending-balance does not exist
				\XBRL_Log::getInstance()->formula_validation( "Formula precision value", "Failed to compile expression",
					array(
						'qname expression' => $this->precisionRule,
						'error' => $ex instanceof XPath2Exception ? ( $ex->ErrorCode == 'XPST0017' ? "err:XPST0017" : $ex->ErrorCode ) : get_class( $ex ),
						'reason' => $ex->getMessage()
					)
				);
			}
		}

		// If there is no source then concept MUST be explicitly declared
		if ( is_null( $this->source ) )
		{
			if ( is_null( $this->conceptRule ) )
			{
				$log->formula_validation( "Formula", "If there is no source then a concept aspect rule MUST be explicitly declared but is not provided",
					array(
						'formula' => $this->label,
						'error' => 'xbrlfe:missingConceptRule'
					)
				);
			}

			if ( is_null( $this->entityIdentifierRule ) )
			{
				$log->formula_validation( "Formula", "If there is no source then an entity aspect rule MUST be explicitly declared but is not provided",
					array(
						'formula' => $this->label,
						'error' => 'xbrlfe:missingEntityIdentifierRule'
					)
				);
			}

			if ( is_null( $this->periodRule ) )
			{
				$log->formula_validation( "Formula", "If there is no source then an period aspect rule MUST be explicitly declared but is not provided",
					array(
						'formula' => $this->label,
						'error' => 'xbrlfe:missingPeriodRule'
					)
				);
			}

			// Create a qname from either the qname or the expression
			/**
			 * @var QName $qname
			 */
			$qname = null;
			if ( $this->conceptRule['qnameExpression'] )
			{
				foreach ( $this->conceptRule['qnameExpression'] as $qnameExpression )
				{
					// Check any variables in the expression are valid
					$expression = XPath2Expression::Compile( $qnameExpression, $this->nsMgr );
					$variableRefs = $expression->getParameterQNames();
					foreach ( $variableRefs as $variableQName )
					{
						if ( ! isset( $this->variablesByQName[ $variableQName->clarkNotation() ] ) )
						{
							$log->formula_validation( "Concept rule", "The variable reference in the concept rule qname expression is not to a valid variable",
								array(
									'formula' => $this->label,
									'variable reference' => $variableQName->clarkNotation(),
									'error' => 'xbrlfe:conceptExpressionInvalid'
								)
							);
						}
					}
				}
			}
			else
			{
				$qname = new QName( $this->conceptRule['qname'][0]['originalPrefix'], $this->conceptRule['qname'][0]['namespace'], $this->conceptRule['qname'][0]['name'] );

				// BMS 2018-03-19 Must have been having too many mince pies.  These tests are relevant whenever there is a known concept.
				// 				  They have been moved lower down
				// BMS 2018-01-05 Now not sure why these tests are needed.
	 			// Next find out if the qname refers to a variable.  If it does look for a filter that defines a concept
	 			// Begin by assuming the qname refers to a taxonomy element
	 			$concept = $qname;
	 			if ( isset( $this->variablesByQName[ $concept->clarkNotation() ] ) )
	 			{
	 				/**
	 				 * @var ConceptName $selectedFilter
	 				 */
	 				$selectedFilter = null;
	 				foreach ( $this->variablesByQName[ $concept->clarkNotation() ]->filters as $filter )
	 				{
	 					if ( ! $filter instanceof ConceptName ) continue;
	 					$selectedFilter = $filter;
	 					break;
	 				}

	 				if ( $selectedFilter )
	 				{
						$concept = null;
						$totalFilters = count( $selectedFilter->qnames ) + count( $selectedFilter->qnameExpressions );
						if ( $totalFilters == 1 )
						{
							// It's one of these
							foreach ( $selectedFilter->qnames as $filterQName )
							{
								$concept = qname( $filterQName );
								$taxonomy = $this->xbrlTaxonomy->getTaxonomyForNamespace( $concept->namespaceURI );
								$concept->prefix = $taxonomy->getPrefix();
							}

							if ( ! $concept )
							{
								foreach ( $selectedFilter->qnameExpressions as $filterQNameExpression )
				 				{
									$result = $this->evaluateXPath( $this, $this->conceptRule->$filterQNameExpression );
									$concept = new QName( $result->Prefix, $result->NamespaceUri, $result->LocalName );
			 					}
							}
						}

						if ( $totalFilters != 1 || ! $concept )
						{
							$log->formula_validation( "Formula", "There is no formula source but the concept aspect rule does not define a reference to a schema element",
								array(
									'formula' => $this->label,
									'error' => 'xbrlfe:missingConceptRule'
								)
							);
						}
	 				}
	 				else
	 				{
	 					// If the concept references a variable and there is no filter then the
	 					// the concept cannot be resolved statically.
	 					$concept = null;
	 				}
				}

				if ( $concept )
				{
					// BMS 2017-12-24 Move the following tests here because surely they are only relevant when there is no formula source
					/**
					 * @var SchemaTypes $types
					 */
					$types = \XBRL_Types::getInstance();
					$conceptElement = $this->xbrlTaxonomy->getElementByName( $concept->localName );
					// Or could do it this way
					// $conceptElement = $types->getElement( $this->conceptRule['qname'][0]['name'], $this->conceptRule['qname'][0]['originalPrefix'] );
					// $isNumeric = $types->resolvesToBaseType( $conceptElement['types'][0], array( 'xs:decimal', 'xs:decimal' ) );
					if ( ! $conceptElement )
					{
						$log->formula_validation( "Formula", "The concept provided by the concept aspect rule is not a valid schema element",
							array(
								'formula' => $label,
								'error' => 'xbrlfe:missingConceptRule'
							)
						);
					}

					// BMS 2018-04-09 Extra test candidate not required any more but it doesn't hurt.
					$isNumeric = $types->resolvesToBaseType( $conceptElement['type'], array( 'xs:decimal', 'xsd:decimal' ) );
					if ( is_null( $this->source ) && is_null( $this->unitRule ) )
					{
						// Check to see if the concept references a numeric type
						if ( $isNumeric )
						{
							$log->formula_validation( "Formula", "If there is no source and the concept references a numeric type then a unit aspect rule MUST be explicitly declared but is not provided",
								array(
									'formula' => $this->label,
									'error' => 'xbrlfe:missingUnitRule'
								)
							);
						}
					}
					else if ( ! is_null( $this->unitRule ) )
					{
						if ( ! $isNumeric )
						{
							$log->formula_validation( "Formula", "The concept aspect rule defines a non-numeric concept so a unit is not valid",
								array(
									'formula' => $this->label,
									'error' => 'xbrlfe:conflictingAspectRules'
								)
							);
						}
					}

					// BMS 2018-03-19 Don't know why this is here when it is defined below
					// // Make sure there is no conflict between the concept and period aspect rule
					// if ( ! is_null( $this->periodRule ) )
					// {
					// 	if ( ! is_null( $this->periodRule['rav'] ) && $this->periodRule['rav'] != $conceptElement['periodType'] )
					// 	{
					// 		$log->formula_validation( "Formula", "The type of the period aspect rule conflicts with the period type of the concept aspect rule",
					// 			array(
					// 				'period aspect type' => $this->periodRule['rav'],
					// 				'concept period type' => $conceptElement['periodType'],
					// 				'formula' => $this->label,
					// 				'error' => 'xbrlfe:conflictingAspectRules'
					// 			)
					// 		);
					// 	}
					// }
				}
			}
		}
		else // $source is not null
		{
			$sourceQName = new QName( $this->source['originalPrefix'], $this->source['namespace'], $this->source['name'] );

			// If the if the source is not the uncovered qname make sure the referenced variable exists
			// if ( $sourceQName->namespaceURI != \XBRL_Constants::$standardPrefixes[ STANDARD_PREFIX_FORMULA ] ||
			//	 $sourceQName->localName != "uncovered" )
			if ( ! $this->getIsFormulaUncoveredQName( $sourceQName ) )
			{
				if ( ! isset( $this->variablesByQName[ $sourceQName->clarkNotation() ] ) ||
					 ! $this->variablesByQName[ $sourceQName->clarkNotation() ] instanceof FactVariable
				)
				{
					$log->formula_validation( "Formula", "",
						array(
							'concept' => $sourceQName->prefix ? "{$sourceQName->prefix}:{$sourceQName->localName}" : $sourceQName->localName,
							'formula' => $this->label,
							'error' => 'xbrlfe:nonexistentSourceVariable',
						)
					);
				}

				/**
				 * Look for the variable
				 * @var FactVariable $variable
				 */
				$variable = $this->variablesByQName[ $sourceQName->clarkNotation() ];
				if ( $variable->bindAsSequence )
				{
					// TODO Should check the XPath implied by the fallback value but, for now,
					//	    copy Arelle and fail if there is any fallback value
					$log->formula_validation( "Formula", "Formula source is a fact variable that binds as a sequence",
						array(
							'formula' => $this->label,
							'source' => $sourceQName->prefix ? "{$sourceQName->prefix}:{$sourceQName->localName}" : $sourceQName->localName,
							'error' => 'xbrlfe:defaultAspectValueConflicts',
						)
					);
				}
			}

			if ( $this->conceptRule['qname'] )
			{
				// BMS 2015-03-26
				// If the concept rule is really a source then the qname will reference a variable so reset
				$concept = new QName( $this->conceptRule['qname'][0]['originalPrefix'], $this->conceptRule['qname'][0]['namespace'], $this->conceptRule['qname'][0]['name'] );
				if ( isset( $this->variablesByQName[ $concept->clarkNotation() ] ) )
				{
					$concept = null;
				}
			}
		}

		if ( isset( $concept ) )
		{
			// BMS 2018-03-19 Must have been having too many mince pies.  These tests are relevant whenever there is a known concept.
			// 				  So they belong here.
			// BMS 2017-12-24 Move the following tests here because surely they are only relevant when there is no formula source
			$types = \XBRL_Types::getInstance();
			$conceptElement = $this->xbrlTaxonomy->getElementByName( $concept->localName );
			// Or could do it this way
			// $conceptElement = $types->getElement( $this->conceptRule['qname'][0]['name'], $this->conceptRule['qname'][0]['originalPrefix'] );
			// $isNumeric = $types->resolvesToBaseType( $conceptElement['types'][0], array( 'xs:decimal', 'xsd:decimal' ) );
			if ( ! $conceptElement )
			{
				$log->formula_validation( "Formula", "The concept provided by the concept aspect rule is not a valid schema element",
					array(
						'formula' => $label,
						'error' => 'xbrlfe:missingConceptRule'
					)
				);
			}

			// BMS 2018-04-09 Extra test candidate not required any more but it doesn't hurt.
			$isNumeric = $types->resolvesToBaseType( $conceptElement['type'], array( 'xs:decimal', 'xsd:decimal' ) );
			if ( is_null( $this->source ) && is_null( $this->unitRule ) )
			{
				// Check to see if the concept references a numeric type
				if ( $isNumeric )
				{
					$log->formula_validation( "Formula", "If there is no source and the concept references a numeric type then a unit aspect rule MUST be explicitly declared but is not provided",
						array(
							'formula' => $this->label,
							'error' => 'xbrlfe:missingUnitRule'
						)
					);
				}
			}
			else if ( ! is_null( $this->unitRule ) )
			{
				if ( ! $isNumeric )
				{
					$log->formula_validation( "Formula", "The concept aspect rule defines a non-numeric concept so a unit is not valid",
						array(
							'formula' => $this->label,
							'error' => 'xbrlfe:conflictingAspectRules'
						)
					);
				}
			}

			// Make sure there is no conflict between the concept and period aspect rule
			if ( ! is_null( $this->periodRule ) )
			{
				if ( ! is_null( $this->periodRule['rav'] ) && $this->periodRule['rav'] != $conceptElement['periodType'] )
				{
					$log->formula_validation( "Formula", "The type of the period aspect rule conflicts with the period type of the concept aspect rule",
						array(
							'period aspect type' => $this->periodRule['rav'],
							'concept period type' => $conceptElement['periodType'],
							'formula' => $this->label,
							'error' => 'xbrlfe:conflictingAspectRules'
						)
					);
				}
			}

		}

		$sources = $this->getAspectSources();
		foreach ( $sources as $ruleName => $source )
		{
			if ( $this->getIsFormulaUncoveredQName( $source ) ) continue;

			$sourceQName = new QName( $source['originalPrefix'], $source['namespace'], $source['name'] );
			/**
			 * Look for the variable
			 * @var FactVariable $variable
			 */
			$variable = $this->variablesByQName[ $sourceQName->clarkNotation() ];
			if ( ! $variable->fallbackValue ) continue;

			// TODO Should check the XPath implied by the fallback value but, for now,
			//	    copy Arelle and fail if there is any fallback value
			$log->formula_validation( "Formula aspects", "Formula source is a fact variable that has a fallback value",
				array(
					'formula' => $this->label,
					'rule' => $ruleName,
					'error' => 'xbrlfe:bindEmptySourceVariable',
				)
			);
		}

		return true;
	}
1169111
public T validateNamespace(String prefix, String namespaceUri) {
        xmlMessageValidationContext.getControlNamespaces().put(prefix, namespaceUri);
        return self;
    }
428345
public static function check(string $variableName = '_MF_SESSION_INTEGRITY_TOKEN_'): bool
    {
        static::init();
        $variableName = (string)$variableName;
        $vHandler = Variables::getInstance();
        $userToken = $vHandler->session->get($variableName, $vHandler::TYPE_STRING);
        $httpReferer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
        $rIntegrity = static::$refererIntegrityEnabled ? \stripos($httpReferer, static::$serverName) !== false : true;
        $tIntegrity = static::$tokenIntegrityEnabled ? $userToken === static::buildToken() : true;
        return $rIntegrity && $tIntegrity;
    }
1136986
private function validateParameters( $taxonomy, $contextParameters, $variableSet )
	{
		$parameterArcs = $taxonomy->getGenericArc( XBRL_Constants::$arcRoleVariableSet, $variableSet->extendedLinkRoleUri, null, $variableSet->path, null, $variableSet->linkbase );

		// Get any variable sets.  These will be headed by a formula.
		$parameters = array_filter( $taxonomy->getGenericResource( 'variable',  'parameter', null, null, null /*, $variableSet->linkbase */ ),
			function( $resource ) use( $parameterArcs )
			{
				return count( array_filter( $parameterArcs, function( $arc ) use( $resource )
				{
					return $arc['tolinkbase'] == $resource['linkbase'];
				} ) ) > 0;
			}
		);

		// Check there are parameters to process
		if ( ! $parameters ) return true;

		$parameterDependencies = array();

		foreach ( $parameters as $parameterReference )
		{
			/** @var Parameter $parameter */
			$parameter = Parameter::fromArray( $parameterReference['variable'] );
			if ( ! $parameter )
			{
				$this->log->err( "Failed to create Parameter instance from an array" );
				return false;
			}

			if ( $parameter->path != $variableSet->path ) continue;

			if ( ! $parameter->validate( null, $this->nsMgr ) )
			{
				return false;
			}

			$parameterDependencies[ $parameter->getQName()->clarkNotation() ] = $parameter->getVariableRefs();

			$this->parameterQnames[ $parameter->getQName()->clarkNotation() ] = $parameter;
			$variableSet->parameters[ $parameter->getQName()->clarkNotation() ] = $parameter;
		}

		/**
		 * Examines parameter dependcies
		 * @var Function $hasCircularReference
		 */
		$parameterQnames = $this->parameterQnames;
		$hasCircularReference = function( $dependencies, $history = array() ) use( &$hasCircularReference, $parameterDependencies, $parameterQnames )
		{
			foreach ( $dependencies as /** @var QName $dependency */ $dependency )
			{
				// Check if this is a cyclic reference
				if ( in_array( $dependency, $history ) )
				{
					$this->log->formula_validation( 'Variable parameter', 'Cyclic dependencies in parameter names to names dependencies', array(
						'parameter' => end( $history ),
						'dependency' => $dependency->clarkNotation(),
						'error' => 'xbrlve:parameterCyclicDependencies'
					) );

					return true;
				}

				// The dependency MUST appear in $parameterQnames or it is undefined
				if ( ! isset( $parameterQnames[ $dependency->clarkNotation() ] ) )
				{
					$this->log->formula_validation( 'Variable parameter', 'Undefined dependencies in parameter to names dependencies', array(
						'parameter' => end( $history ),
						'dependency' => $dependency->clarkNotation(),
						'error' => 'xbrlve:unresolvedDependency'
					) );
					return true;
				}

				// Look for the dependency in $parameterDependencies
				if ( ! isset( $parameterDependencies[ $dependency->clarkNotation() ] ) )
				{
					continue;
				}

				// Check the next dependencies
				$history[] = $dependency->clarkNotation();
				if ( $hasCircularReference( $parameterDependencies[ $dependency->clarkNotation() ], $history ) )
				{
					return true;
				}
			}

			return false;
		};

		// Perform the dependency check
		foreach ( $parameterDependencies as $qname => $dependencies )
		{
			if ( $hasCircularReference( $dependencies, array( $qname ) ) )
			{
				return false;
			}
		}

		// Check there is a context parameter for each formula parameter that is marked as required
		foreach ( $this->parameterQnames as $clark => /** @var Parameter $parameter */ $parameter )
		{
			// If the parameter references a qname from the the instance then there is nothing to do here
			if ( $taxonomy->getElementByName( $parameter->getQName()->localName ) ) continue;

			try
			{
				// Check to see if the parameter is one of the context (passed in) parameters
				if ( isset( $contextParameters[ $clark ] ) )
				{
					// Test the compatibility of the context parameter type and value
					$parameter->select = $contextParameters[ $clark ]['value'];
					$expression = XPath2Expression::Compile( "{$contextParameters[ $clark ]['datatype']}({$contextParameters[ $clark ]['value']}) cast as {$contextParameters[ $clark ]['datatype']}", $this->nsMgr );
					$value = $expression->EvaluateWithVars( null, array() );
					$parameter->expression = $expression;

					// Now check the $value type is compatible with the parameter type.
					// The evaluation step will throw an exception if not
					if ( $parameter->as )
					{
						$expression = XPath2Expression::Compile( "\$value cast as {$parameter->as}", $this->nsMgr );
						$result = $expression->EvaluateWithVars( null, array( 'value' => $value ) );
						// Replace with casted expression if valid
						// $parameter->expression = $expression;
					}
				}
				else if ( $parameter->required )
				{
					$this->log->formula_validation( 'Variable parameter', 'Parameter is required but not input', array(
						'parameter' => $clark,
						'error' => 'xbrlve:missingParameterValue'
					) );

					return false;
				}
				else if ( ! isset( $parameter->select ) || ! strlen( $parameter->select ) )
				{
					$this->log->formula_validation( 'Variable parameter', 'Parameter does not have a select attribute', array(
						'parameter' => $clark,
						'error' => 'xbrlve:missingParameterValue'
					) );

					return false;
				}
			}
			catch ( Exception $ex )
			{
				$this->log->formula_validation( 'Variable parameter', 'The input parameter type is not valid', array(
					'parameter' => $clark,
					'cause' => $ex->getMessage(),
					'error' => 'xbrlve:parameterTypeMismatch'
				) );

				return false;
			}
		}

		// TODO This needs to be checked
		// There should be no dependencies so this routine should resolve all parameter expressions to result values.
		$parameters = $this->parameterQnames;
		while ( $parameters )
		{
			// Get the first parameter
			$parameter = reset( $parameters );
			unset( $parameters[ key( $parameters ) ] );

			 // Get a list of dependencies for this parameter
			$dependencies = $parameter->getVariableRefs();

			$vars = array();

			// Make sure that each dependency has been evaluated
			foreach ( $dependencies as $qname => $dependentQName )
			{
				if ( ! isset( $this->parameterQnames[ $dependentQName->clarkNotation() ] ) )
				{
					continue;
				}

				$dependentParameter = $this->parameterQnames[ $dependentQName->clarkNotation() ];
				if ( ! $dependentParameter->result ) continue;

				$vars[ $dependentParameter->name ] = $dependentParameter->result;
			}

			try
			{
				$result = $parameter->expression->EvaluateWithVars( null, $vars );
				$parameter->result = $result;
			}
			catch ( Exception $ex )
			{
				$this->log->formula_validation( 'Variable parameter', 'Parameter type is not valid', array(
					'parameter' => $parameter->getQName()->clarkNotation(),
					'select' => $parameter->getSelectAsExpression(),
					'as' => $parameter->as,
					'cause' => $ex->getMessage(),
					'error' => 'xbrlve:parameterTypeMismatch'
				) );
			}

		}

		return true;
	}
1046966
public function toQuery( $variableSet, $factVariableBinding )
	{
		$variable = new QName( $this->variable['originalPrefix'], $this->variable['namespace'], $this->variable['name'] );

		// Look for this variable among the bindings.  If it exists
		// and has a fallback value the the query is just false()
		if ( isset( $variableSet->factVariableBindings[ $variable->clarkNotation() ] ) )
		{
			/**
			 * @var FactVariableBinding $binding
			 */
			$binding = $variableSet->factVariableBindings[ $variable->clarkNotation() ];
			if ( $binding->isFallback )
			{
				return "false()";
			}
		}
		else // BMS 201803-07 What else could it be? if ( isset( $variableSet->generalVariableBindings[ $variable->clarkNotation() ] ) )
		{
			return "false()";
		}

		$this->allowAspectsCovered = true;
		$result = parent::toQuery( $variableSet, $factVariableBinding );
		// Once the filter has been created the class should return the filters applied
		// $this->allowAspectsCovered = false;

		return $result;
	}
1332183
public function getAspectsCovered( $variableSet, $factVariableBinding )
	{
		if ( $this->dimension )
		{
			// $qname = qname( $this->dimension );
			return array( "{{$this->dimension['namespace']}}{$this->dimension['name']}" );
		}
		else if ( $this->dimensionXPath2Expression )
		{
			/**
			 * @var XPath2Item $result
			 */
			$result = $this->evaluateXPathExpression( $variableSet, $this->dimensionXPath2Expression );
			return array( (string)$result->getValue() );
		}
		else if ( $this->dimensionExpression )
		{
			/**
			 * @var XPath2Item $result
			 */
			$result = $this->evaluateXPath( $variableSet, $this->dimensionExpression );
			return array( (string)$result->getValue() );
		}

		return array( ASPECT_DIMENSIONS );
	}
272217
public function validate( $variableSet, $nsMgr )
	{
		if ( isset( $this->test ) && ! empty( $this->test ) )
		{
			try
			{
				$expression = XPath2Expression::Compile( $this->test, $nsMgr );
				$this->testXPath2Expression = $expression;
			}
			catch ( Exception $ex )
			{
				\XBRL_Log::getInstance()->valueassertion_validation( "Value assertion", "Failed to compile test expression",
					array(
						'test expression' => $this->test,
						'error' => $ex instanceof XPath2Exception ? $ex->ErrorCode : get_class( $ex ),
						'reason' => $ex->getMessage()
					)
				);

				return false;
			}

		}

		return true;
	}
864267
public function Filter( $facts, $variableSet )
	{
		// Look for the variable
		$vars = $variableSet->getBindingsAsVars();
		$clark = str_replace( "{}", "", "{{$this->variable['namespace']}}{$this->variable['name']}" );
		if ( ! isset( $vars[ $clark ] ) )
		{
			// Should probably throw some kind of error here
			throw XPath2Exception::withErrorCodeAndParam( "XPST0008", Resources::XPST0008, $clark );
		}

		/**
		 * @var \DOMNode[] $candidates
		 */
		$candidates = array();
		$var = $vars[ $clark ];
		if ( $var instanceof XPath2NodeIterator )
		{
			$candidates = array_map( function( $node ) { return $node->getUnderlyingObject(); }, $var->ToList() );
		}
		else
		{
			$candidates[] = $var->getUnderlyingObject();
		}

		$dom = dom_import_simplexml( $variableSet->xbrlInstance->getInstanceXml() );
		$doc = $dom->ownerDocument;
		$xpath = new \DOMXPath( $doc );

		$matched = array();
		$notMatched = array();

		foreach ( $facts as $fact )
		{
			$node = $fact->getUnderlyingObject();

			/**
			 * @var \DOMNode[] $candidates
			 */
			$locations = $xpath->query( $this->location, $node );

			// See if any $candidates and any $locations overlap
			foreach ( $candidates as /** @var \DOMElement $candidate */ $candidate )
			{
				foreach ( $locations as /** @var \DOMElement $location */ $location )
				{
					if ( $candidate->isSameNode( $location ) )
					{
						$matched[] = $fact->CloneInstance();
						continue 3;
					}
				}
			}

			$notMatched[] = $fact->CloneInstance();
		}

		return DocumentOrderNodeIterator::fromItemset( $this->complement ? $notMatched : $matched );

		return $facts;
	}
385910
public function validate( $variableSet, $nsMgr )
	{
		$log = \XBRL_Log::getInstance();

		if ( $this->fallbackValue )
		{
			$xpath2Expression = XPath2Expression::Compile( $this->fallbackValue, $nsMgr );
			$qnames = $xpath2Expression->getParameterQNames();
			if ( $qnames )
			{
				foreach ( $qnames as $key => $qname )
				{
					// Only parameters allowed
					if ( isset( $variableSet->variablesByQName[ (string)$qname ] ) )
					{
						$log->formula_validation( "variables", "Variable references are not allowed in fallback expression",
							array(
								'error' => 'xbrlve:fallbackValueVariableReferenceNotAllowed',
							)
						);
					}
				}
			}
		}

		// Check any aspect cover filters for consistency
		$aspectCovers = array();
		foreach ( $this->filters as $filter )
		{
			if ( ! $filter instanceof AspectCover ) continue;
			foreach ( $filter->getAspectsCovered( $variableSet, null ) as $aspectCovered )
			{
				if ( isset( $aspectCovers[ $aspectCovered ] ) )
				{
					// If the cover values are the same then continue otherwise report an error
					if ( $aspectCovers[ $aspectCovered ] == $filter->cover ) continue;

					$log->formula_validation( "aspect cover filter", "cover value across filters is different for the same aspect",
						array(
							'error' => 'xbrlacfe:inconsistentAspectCoverFilters',
							'filter' => $filter->label,
							'aspect' => $aspectCovered,
						)
					);
				}
				else
				{
					$aspectCovers[ $aspectCovered ] = $filter->cover;
				}
			}
		}

		return parent::validate( $variableSet, $nsMgr );
	}
802129
public static function CreateQName( $context, $ns, $qname )
	{
		if ( $ns instanceof Undefined )
		{
			$ns = "";
		}

		$ns = trim( $ns );
		$qname = trim( $qname );

		if ( empty( $ns ) && strpos( $qname, ":" ) )
		{
			throw XPath2Exception::withErrorCodeAndParam( "FOCA0002", Resources::FOCA0002, $qname );
		}

		// $qn = \lyquidity\xml\qname( $ns, $qname );
		if ( strpos( $qname, ":") !== false )
		{
			$parts = explode( ":", $qname );
			$qn = new \lyquidity\xml\qname( $parts[0], $ns, $parts[1] );
		}
		else
		{
			$prefix = $context->NamespaceManager->lookupPrefix( $ns );
			$qn = new \lyquidity\xml\qname( $prefix ? $prefix : "", $ns, $qname );
		}
		return QNameValue::fromQName( $qn );
	}
372614
public static function ResolveQName( $context, $qname, $nav )
	{
		if ( $qname instanceof Undefined )
		{
			return Undefined::getValue();
		}

	    /**
	     * @var XmlNamespaceManager $nsmgr
	     */
		$nsmgr = new XmlNamespaceManager( $context->NameTable );
		ExtFuncs::ScanLocalNamespaces( $nsmgr, $nav->CloneInstance(), true );
		// $qNameValue = QNameValue::fromQName( \lyquidity\xml\qname( $qname . "", $nsmgr->getNamespaces() ) );
		$qNameValue = QNameValue::fromNCName( $qname, $nsmgr );
		return XPath2Item::fromValue( $qNameValue );
	}