Generate a set of rules to be applied at the root of a document

@param  array $tagInspectors Array of [tagName => TemplateInspector]
@return array
170509
protected function generateRootRules(array $tagInspectors)
	{
		// Create a proxy for the parent markup so that we can determine which tags are allowed at
		// the root of the text (IOW, with no parent) or even disabled altogether
		$rootInspector = new TemplateInspector('<div><xsl:apply-templates/></div>');
		$rules         = $this->generateRuleset($rootInspector, $tagInspectors);

		// Remove root rules that wouldn't be applied anyway
		unset($rules['autoClose']);
		unset($rules['autoReopen']);
		unset($rules['breakParagraph']);
		unset($rules['closeAncestor']);
		unset($rules['closeParent']);
		unset($rules['fosterParent']);
		unset($rules['ignoreSurroundingWhitespace']);
		unset($rules['isTransparent']);
		unset($rules['requireAncestor']);
		unset($rules['requireParent']);

		return $rules;
	}
663086
private function getProcessedTagRules(): array
    {
        if ($this->processedTagRules === null) {
            $this->processedTagRules = $this->processTagRules();
        }

        return $this->processedTagRules;
    }
1202056
protected function getPrefixes(array $tagNames)
	{
		$prefixes = [];
		foreach ($tagNames as $tagName)
		{
			$pos = strpos($tagName, ':');
			if ($pos !== false)
			{
				$prefixes[substr($tagName, 0, $pos)] = 1;
			}
		}
		$prefixes = array_keys($prefixes);
		sort($prefixes);

		return $prefixes;
	}
296474
final public function get_layout_definition() : array {

		$standard_fields = [];
		// Add heading field to module.
		if ( true === apply_filters( 'hogan/module/' . $this->name . '/heading/enabled', false ) ) {
			hogan_append_heading_field( $standard_fields, $this );
		}

		// Add lead field to module.
		if ( true === apply_filters( 'hogan/module/' . $this->name . '/lead/enabled', false ) ) {
			hogan_append_lead_field( $standard_fields, $this );
		}

		$sub_fields = array_merge(
			apply_filters( 'hogan/module/' . $this->name . '/fields_before', [] ),
			$standard_fields,
			$this->get_fields(),
			apply_filters( 'hogan/module/' . $this->name . '/fields_after', [] )
		);

		return [
			'key'        => $this->field_key,
			'name'       => $this->name,
			'label'      => $this->label,
			'display'    => apply_filters( 'hogan/module/' . $this->name . '/layout/display', 'block' ),
			'sub_fields' => apply_filters( 'hogan/module/' . $this->name . '/layout/sub_fields', $sub_fields ),
			'min'        => apply_filters( 'hogan/module/' . $this->name . '/layout/min', '' ),
			'max'        => apply_filters( 'hogan/module/' . $this->name . '/layout/max', '' ),
		];
	}
760914
private static function prepareRules(array $rules)
    {
        $mergedRules = [];

        foreach ($rules as $ruleFields => $ruleConditions) {

            //if set of fields like 'firstname, lastname...'
            if (strpos($ruleFields, ',') !== false) {
                foreach (explode(',', $ruleFields) as $fieldName) {
                    $fieldName = trim($fieldName);

                    if (!isset($mergedRules[$fieldName])) {
                        $mergedRules[$fieldName] = $ruleConditions;
                    } else {
                        $mergedRules[$fieldName] .= '|'.$ruleConditions;
                    }
                }
            } else {
                if (!isset($mergedRules[$ruleFields])) {
                    $mergedRules[$ruleFields] = $ruleConditions;
                } else {
                    $mergedRules[$ruleFields] .= '|'.$ruleConditions;
                }
            }
        }

        $finalRules = [];

        //remove duplicated rules, like 'required|alpha|required'
        foreach ($mergedRules as $newRule => $rule) {
            $finalRules[$newRule] = implode('|', array_unique(explode('|', $rule)));
        }

        return $finalRules;
    }
1069219
private function buildExtensions(SimpleXMLElement $phpDocumentor): array
    {
        if ((array) $phpDocumentor->parser === []) {
            return $this->extensions;
        }

        if ((array) $phpDocumentor->parser->extensions === []) {
            return $this->extensions;
        }

        return $this->buildArrayFromNode($phpDocumentor->parser->extensions);
    }
503731
public function parse(array $tokens)
    {
        $parser = new Parser($this->symbolContainer);

        if ($this->customGrammarChecker !== null) {
            $parser->setCustomGrammarChecker($this->customGrammarChecker);
        }

        $rootNode = $parser->parse($tokens);

        return $rootNode;
    }
337807
private function mapNodes(\DOMNodeList $elements)
    {
        $nodes = [];

        foreach ($elements as $element) {
            $node = $this->mapNode($element);
            $nodes[$node->getId()] = $node;
        }

        return $nodes;
    }
1234301
protected function getElements($tagName)
	{
		$nodes = [];
		foreach ($this->template->ownerDocument->getElementsByTagName($tagName) as $node)
		{
			if (!$this->onlyIfDynamic || $this->isDynamic($node))
			{
				$nodes[] = $node;
			}
		}

		return $nodes;
	}
1071293
private function getRelatedObjectIds(DOMDocument $xml, array $tagNames): array
    {
        $contentIds = [];
        $locationIds = [];

        $xpath = new DOMXPath($xml);
        $xpath->registerNamespace('docbook', 'http://docbook.org/ns/docbook');
        foreach ($tagNames as $tagName) {
            $xpathExpression = "//docbook:{$tagName}[starts-with( @xlink:href, 'ezcontent://' ) or starts-with( @xlink:href, 'ezlocation://' )]";
            /** @var \DOMElement $element */
            foreach ($xpath->query($xpathExpression) as $element) {
                preg_match('~^(.+)://([^#]*)?(#.*|\\s*)?$~', $element->getAttribute('xlink:href'), $matches);
                list(, $scheme, $id) = $matches;

                if (empty($id)) {
                    continue;
                }

                if ($scheme === 'ezcontent') {
                    $contentIds[] = $id;
                } elseif ($scheme === 'ezlocation') {
                    $locationIds[] = $id;
                }
            }
        }

        return [
            'locationIds' => array_unique($locationIds),
            'contentIds' => array_unique($contentIds),
        ];
    }
624900
private function generateFillSlots(PHPTAL_Php_CodeWriter $codewriter, PHPTAL_Dom_Node $phpelement)
    {
        if (false == ($phpelement instanceof PHPTAL_Dom_Element)) {
            return;
        }

        // if the tag contains one of the allowed attribute, we generate it
        foreach (self::$ALLOWED_ATTRIBUTES as $qname => $uri) {
            if ($phpelement->hasAttributeNS($uri, $qname)) {
                $phpelement->generateCode($codewriter);
                return;
            }
        }

        foreach ($phpelement->childNodes as $child) {
            $this->generateFillSlots($codewriter, $child);
        }
    }
569572
private function loadTagTokens(): array
    {
        $barrier = 0;
        $tokens = $this->docTagHelper->getTagTokens();

        $tokens = array_filter($tokens, function (array $token) use (&$barrier): bool {
            $allowed = true;

            if ($barrier) {
                if ($allowed = $token['column'] <= $barrier) {
                    $barrier = 0;
                }
            }

            if ($allowed && array_key_exists('contents', $token)) {
                $barrier = $token['column'];
            }

            return $allowed;
        });

        return $tokens;
    }
950842
public function getRules(TagCollection $tags)
	{
		$tagInspectors = $this->getTagInspectors($tags);

		return [
			'root' => $this->generateRootRules($tagInspectors),
			'tags' => $this->generateTagRules($tagInspectors)
		];
	}
16366
protected function setEntityRules($rules = [])
    {
        $this->entityLocalRules = $rules;
        $cache = $this->getCache();
        if ($cache) {
            $tagDependency = new TagDependency(
                ['tags' => [$this->getEntityRulesCacheTag()]]
            );
            $cache->set($this->getEntityRulesCacheKey(), $rules, 0, $tagDependency);
        }
    }
632233
public function getTemplates()
	{
		$templates = [
			'br' => '<br/>',
			'e'  => '',
			'i'  => '',
			'p'  => '<p><xsl:apply-templates/></p>',
			's'  => ''
		];

		foreach ($this->configurator->tags as $tagName => $tag)
		{
			if (isset($tag->template))
			{
				$templates[$tagName] = (string) $tag->template;
			}
		}

		ksort($templates);

		return $templates;
	}
1063282
public function getTemplateAuthItems()
    {
        $rule = new \nineinchnick\nfy\components\SubscribedRule;
        return [
            ['name' => 'nfy.queue.read',              'bizRule' => null, 'child' => null],
            ['name' => 'nfy.queue.read.subscribed',   'bizRule' => $rule->name, 'child' => 'nfy.queue.read'],
            ['name' => 'nfy.queue.subscribe',         'bizRule' => null, 'child' => null],
            ['name' => 'nfy.queue.unsubscribe',       'bizRule' => null, 'child' => null],
            ['name' => 'nfy.message.read',              'bizRule' => null, 'child' => null],
            ['name' => 'nfy.message.create',            'bizRule' => null, 'child' => null],
            ['name' => 'nfy.message.read.subscribed',   'bizRule' => $rule->name, 'child' => 'nfy.message.read'],
            ['name' => 'nfy.message.create.subscribed', 'bizRule' => $rule->name, 'child' => 'nfy.message.create'],
        ];
    }
806353
public function getTemplateInheritors()
    {
        $templateInheritors = [];
        foreach ($this->inheritors as $inheritor) {
            if ($inheritor instanceof self) {
                $templateInheritors[] = $inheritor;
            }
        }

        return $templateInheritors;
    }