Links the content object attribute and tag

@static

@param eZContentObjectAttribute $attribute
@param eZTagsObject $tagObject
@param string $keyword
@param string $locale
760266
static private function linkTag( eZContentObjectAttribute $attribute, eZTagsObject $tagObject, $keyword, $locale, $priority )
    {
        $languageID = eZContentLanguage::idByLocale( $locale );
        if ( $languageID === false )
            return;

        if ( $locale == $attribute->attribute( 'language_code' ) )
        {
            if ( !$tagObject->hasTranslation( $locale ) )
            {
                $tagKeywordObject = new eZTagsKeyword( array(
                    'keyword_id'  => $tagObject->attribute( 'id' ),
                    'language_id' => $languageID,
                    'keyword'     => $keyword,
                    'locale'      => $locale,
                    'status'      => eZTagsKeyword::STATUS_PUBLISHED ) );
                $tagKeywordObject->store();
                $tagObject->updateLanguageMask();
            }
        }

        $linkObject = new eZTagsAttributeLinkObject( array(
            'keyword_id'              => $tagObject->attribute( 'id' ),
            'objectattribute_id'      => $attribute->attribute( 'id' ),
            'objectattribute_version' => $attribute->attribute( 'version' ),
            'object_id'               => $attribute->attribute( 'contentobject_id' ),
            'priority'                => $priority ) );
        $linkObject->store();
    }
455437
static public function createFromStrings( eZContentObjectAttribute $attribute, $idString, $keywordString, $parentString, $localeString )
    {
        $idArray = explode( '|#', $idString );
        $keywordArray = explode( '|#', $keywordString );
        $parentArray = explode( '|#', $parentString );
        $localeArray = explode( '|#', $localeString );

        $wordArray = array();
        foreach ( array_keys( $idArray ) as $key )
        {
            $wordArray[] = trim( $idArray[$key] ) . "|#" . trim( $keywordArray[$key] ) . "|#" . trim( $parentArray[$key] ) . "|#" . trim( $localeArray[$key] );
        }

        $idArray = array();
        $keywordArray = array();
        $parentArray = array();
        $localeArray = array();

        $db = eZDB::instance();

        $wordArray = array_unique( $wordArray );
        foreach ( $wordArray as $wordKey )
        {
            $word = explode( '|#', $wordKey );
            if ( $word[0] != '' )
            {
                $idArray[] = (int) $word[0];
                $keywordArray[] = trim( $word[1] );
                $parentArray[] = (int) $word[2];
                $localeArray[] = trim( $word[3] );
            }
        }

        return new self( $attribute, $idArray, $keywordArray, $parentArray, $localeArray );
    }
812660
protected function _contentAttribute($content = '', $_attributes, $type)
    {
        $type   = strtolower($type);

        $perm   = $this->settings['attr']['perm'] ?? NULL;
        
        $return = '<'.$type.$this->attributes($_attributes).'>'.$this->stringOrCallback($content)."</$type>".EOL;

        $this->outputElement .= $this->_perm($perm, $return);

        return $this;
    }
414319
protected function addAttribute(Tag $tag, $attrName)
	{
		$isUrl = false;
		$exprs = [];
		foreach ($this->captures as $key => $capture)
		{
			if ($capture['name'] !== $attrName)
			{
				continue;
			}
			$exprs[] = $capture['expr'];
			if (isset($this->references['asUrl'][$key]))
			{
				$isUrl = true;
			}
		}
		$exprs = array_unique($exprs);

		$regexp = $this->delimiter . '^';
		$regexp .= (count($exprs) === 1) ? $exprs[0] : '(?:' . implode('|', $exprs) . ')';
		$regexp .= '$' . $this->delimiter . 'D' . $this->modifiers;

		$attribute = $tag->attributes->add($attrName);

		$filter = $this->configurator->attributeFilters['#regexp'];
		$filter->setRegexp($regexp);
		$attribute->filterChain[] = $filter;

		if ($isUrl)
		{
			$filter = $this->configurator->attributeFilters['#url'];
			$attribute->filterChain[] = $filter;
		}
	}
1150986
function createContentObjectAttributeDOMNode( $objectAttribute )
    {
        $dom = new DOMDocument( '1.0', 'utf-8' );

        $node = $dom->createElementNS( 'http://ez.no/object/', 'ezobject:attribute' );

        $node->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:id', $objectAttribute->attribute( 'id' ) );
        $node->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:identifier', $objectAttribute->contentClassAttributeIdentifier() );
        $node->setAttribute( 'name', $objectAttribute->contentClassAttributeName() );
        $node->setAttribute( 'type', $this->isA() );

        return $node;
    }
262896
public function deleteStoredObjectAttribute( $contentObjectAttribute, $version = null )
    {
        $contentObjectAttributeID = $contentObjectAttribute->attribute( 'id' );
        eZTagsAttributeLinkObject::removeByAttribute( $contentObjectAttributeID, $version );
    }
392252
public function transferTagAttributeLinks($tagId, $targetTagId)
    {
        $query = $this->handler->createSelectQuery();
        $query
            ->select('*')
            ->from($this->handler->quoteTable('eztags_attribute_link'))
            ->where(
                $query->expr->eq(
                    $this->handler->quoteColumn('keyword_id'),
                    $query->bindValue($tagId, null, PDO::PARAM_INT)
                )
            );

        $statement = $query->prepare();
        $statement->execute();

        $rows = $statement->fetchAll(PDO::FETCH_ASSOC);

        $updateLinkIds = [];
        $deleteLinkIds = [];

        foreach ($rows as $row) {
            $query = $this->handler->createSelectQuery();
            $query
                ->select(
                    $this->handler->quoteColumn('id')
                )
                ->from($this->handler->quoteTable('eztags_attribute_link'))
                ->where(
                    $query->expr->lAnd(
                        $query->expr->eq(
                            $this->handler->quoteColumn('objectattribute_id'),
                            $query->bindValue($row['objectattribute_id'], null, PDO::PARAM_INT)
                        ),
                        $query->expr->eq(
                            $this->handler->quoteColumn('objectattribute_version'),
                            $query->bindValue($row['objectattribute_version'], null, PDO::PARAM_INT)
                        ),
                        $query->expr->eq(
                            $this->handler->quoteColumn('keyword_id'),
                            $query->bindValue($targetTagId, null, PDO::PARAM_INT)
                        )
                    )
                );

            $statement = $query->prepare();
            $statement->execute();

            $targetRows = $statement->fetchAll(PDO::FETCH_ASSOC);

            if (empty($targetRows)) {
                $updateLinkIds[] = $row['id'];
            } else {
                $deleteLinkIds[] = $row['id'];
            }
        }

        if (!empty($deleteLinkIds)) {
            $query = $this->handler->createDeleteQuery();
            $query
                ->deleteFrom($this->handler->quoteTable('eztags_attribute_link'))
                ->where(
                    $query->expr->in(
                        $this->handler->quoteColumn('id'),
                        $deleteLinkIds
                    )
                );

            $query->prepare()->execute();
        }

        if (!empty($updateLinkIds)) {
            $query = $this->handler->createUpdateQuery();
            $query
                ->update($this->handler->quoteTable('eztags_attribute_link'))
                ->set(
                    $this->handler->quoteColumn('keyword_id'),
                    $query->bindValue($targetTagId)
                )->where(
                    $query->expr->in(
                        $this->handler->quoteColumn('id'),
                        $updateLinkIds
                    )
                );

            $query->prepare()->execute();
        }
    }
520675
protected function takeAttributeFromDOM($attribute)
    {
        switch ($attribute->localName) {
        case 'url':
            $this->_url = $attribute->nodeValue;
            break;
        default:
            parent::takeAttributeFromDOM($attribute);
        }
    }
260496
function storeObjectAttribute( $attribute )
    {
        // create keyword index
        $keyword = $attribute->content();
        if ( is_object( $keyword ) )
        {
            $keyword->store( $attribute );
        }
    }
981219
protected function checkAttributeNode(DOMAttr $attribute, Tag $tag)
	{
		// Parse the attribute value for XPath expressions and assess their safety
		foreach (AVTHelper::parse($attribute->value) as $token)
		{
			if ($token[0] === 'expression')
			{
				$this->checkExpression($attribute, $token[1], $tag);
			}
		}
	}
190715
protected function takeAttributeFromDOM($attribute)
    {
        switch ($attribute->localName) {
            case 'url':
                $this->_url = $attribute->nodeValue;
                break;
            case 'fileSize':
                $this->_fileSize = $attribute->nodeValue;
                break;
            case 'type':
                $this->_type = $attribute->nodeValue;
                break;
            case 'medium':
                $this->_medium = $attribute->nodeValue;
                break;
            case 'isDefault':
                $this->_isDefault = $attribute->nodeValue;
                break;
            case 'expression':
                $this->_expression = $attribute->nodeValue;
                break;
            case 'bitrate':
                $this->_bitrate = $attribute->nodeValue;
                break;
            case 'framerate':
                $this->_framerate = $attribute->nodeValue;
                break;
            case 'samplingrate':
                $this->_samplingrate = $attribute->nodeValue;
                break;
            case 'channels':
                $this->_channels = $attribute->nodeValue;
                break;
            case 'duration':
                $this->_duration = $attribute->nodeValue;
                break;
            case 'height':
                $this->_height = $attribute->nodeValue;
                break;
            case 'width':
                $this->_width = $attribute->nodeValue;
                break;
            case 'lang':
                $this->_lang = $attribute->nodeValue;
                break;
            default:
                parent::takeAttributeFromDOM($attribute);
        }
    }
526998
public function parseXmlTag($tagLib,$tag,$attr,$content) {
        if(ini_get('magic_quotes_sybase'))
            $attr   =   str_replace('\"','\'',$attr);
        $parse      =   '_'.$tag;
        $content    =   trim($content);
        $tags       =   $tagLib->parseXmlAttr($attr,$tag);
        return $tagLib->$parse($tags,$content);
    }
415341
public static function firstByTitleOrCreate($title, $locale = null)
    {
        $tag = Tag::whereTranslation('title', $title, $locale)->first();

        if (is_null($tag))
        {
            $attributes = compact('title');

            if ($locale)
            {
                $attributes = [$locale => $attributes];
            }

            $tag = Tag::create($attributes);
        }

        return $tag;
    }
228826
private function getAttributeTypeMapper(
        string $tagName,
        string $attributeName,
        string $attributeType
    ): AttributeMapper {
        if (isset($this->supportedTagAttributeMappersCache[$attributeType])) {
            return $this->supportedTagAttributeMappersCache[$attributeType];
        }

        foreach ($this->customTagAttributeMappers as $attributeMapper) {
            // get first supporting, order of these mappers is controlled by 'priority' DI tag attribute
            if ($attributeMapper->supports($attributeType)) {
                return $this->supportedTagAttributeMappersCache[$attributeType] = $attributeMapper;
            }
        }

        throw new RuntimeException(
            "RichText Custom Tag configuration: unsupported attribute type '{$attributeType}' of '{$attributeName}' attribute of '{$tagName}' Custom Tag"
        );
    }
540667
public static function tag($tag, $content = null, array $attributes = array())
    {
        return self::openTag($tag, $attributes) . $content . self::closeTag($tag);
    }
536793
public function hasObjectAttributeContent( $contentObjectAttribute )
    {
        /** @var $eZTags eZTags */
        $eZTags = $contentObjectAttribute->content();
        if ( !$eZTags instanceof eZTags )
            return false;

        $tagsCount = $eZTags->attribute( 'tags_count' );
        return $tagsCount > 0;
    }
552032
function objectAttributeContent( $contentObjectAttribute )
    {
        $source = $contentObjectAttribute->attribute( 'data_text' );
        $page = eZPage::createFromXML( $source );

        return $page;
    }