214 lines
No EOL
7.3 KiB
PHP
214 lines
No EOL
7.3 KiB
PHP
<?php
|
|
/**
|
|
* @author Ulrich Hecht <ulrich.hecht@hecht-software.de>
|
|
* @date 02/17/2017
|
|
*/
|
|
|
|
namespace AppBundle\Service;
|
|
|
|
use AppBundle\Entity\Page;
|
|
use AppBundle\Util;
|
|
use Doctrine\ORM\EntityManager;
|
|
|
|
class KeywordService
|
|
{
|
|
protected static $DO_SKIP_KEYWORD_CHECK_BY_DOM_ELEMENT_NAME = ['h1' => true, 'h2' => true, 'h3' => true,
|
|
'h4' => true, 'h5' => true, 'h6' => true, 'a' => true, 'audio' => true, 'video' => true, 'object' => true,
|
|
'nav' => true, 'form' => true
|
|
];
|
|
|
|
private $entityManager;
|
|
private $dictByContext = null;
|
|
private $globalDict = null;
|
|
|
|
/**
|
|
* KeywordService constructor.
|
|
*
|
|
* @param EntityManager $entityManager
|
|
*/
|
|
public function __construct(EntityManager $entityManager)
|
|
{
|
|
$this->entityManager = $entityManager;
|
|
}
|
|
|
|
/**
|
|
* Source: http://78.47.251.156/svn/stern-consulting/sunstarPlugin/branches/1.4/lib/sun.class.php
|
|
*
|
|
* @param $html
|
|
* @param string $classes Space separated values for the "class"-attribute
|
|
* @return string
|
|
*/
|
|
public function addKeywordLinksToHtml($html, $classes = '')
|
|
{
|
|
$dict = $this->getKeywordsToLinksDict($classes);
|
|
$doc = new \DOMDocument('1.0', 'utf-8');
|
|
$doc->loadHTML('<?xml encoding="utf-8" ?><html><body>'. $html .'</body></html>');
|
|
$xp = new \DOMXPath($doc);
|
|
$rootNodes = $xp->query('//body')->item(0)->childNodes;
|
|
$this->addKeywordLinksToDomNodes($rootNodes, $dict, $doc);
|
|
$ret = '';
|
|
foreach($rootNodes as $node)
|
|
{
|
|
$ret .= $doc->saveHTML($node);
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Quelle: http://78.47.251.156/svn/stern-consulting/sunstarPlugin/branches/1.4/lib/sun.class.php
|
|
*
|
|
* @param \DOMNodeList|\DOMNode[] &$nodes
|
|
* @param array &$dict
|
|
* @param \DOMDocument &$doc
|
|
*/
|
|
private function addKeywordLinksToDomNodes(&$nodes, &$dict, &$doc)
|
|
{
|
|
// As $nodes is a direct reference to $parentNode->childNodes it will be changed when
|
|
// replacing text-nodes due to adding keywords. Therefore we loop through this
|
|
// auxilary array '$originalNodes' which simply contains all nodes to process.
|
|
$originalNodes = [];
|
|
foreach ($nodes as $node)
|
|
{
|
|
$originalNodes[] = $node;
|
|
}
|
|
|
|
/** @var \DOMNode $node */
|
|
foreach($originalNodes as $node)
|
|
{
|
|
if($node->nodeType == XML_TEXT_NODE)
|
|
{
|
|
$nodeValue = $node->nodeValue;
|
|
$foundKeywords = false;
|
|
foreach($dict as $keyword => $link)
|
|
{
|
|
$nodeValue = preg_replace('/(^|\W)'. preg_quote($keyword, '/') .'($|\W)/u',
|
|
'$1'. $link .'$2', $nodeValue, 1, $count);
|
|
if($count > 0)
|
|
{
|
|
$foundKeywords = true;
|
|
unset($dict[$keyword]);
|
|
}
|
|
}
|
|
if($foundKeywords)
|
|
{
|
|
$newNode = $doc->createDocumentFragment();
|
|
$newNode->appendXML($nodeValue);
|
|
$node->parentNode->replaceChild($newNode, $node);
|
|
}
|
|
}
|
|
elseif($node->nodeType == XML_ELEMENT_NODE &&
|
|
!isset(self::$DO_SKIP_KEYWORD_CHECK_BY_DOM_ELEMENT_NAME[strtolower($node->nodeName)]))
|
|
{
|
|
$classAttr = $node->attributes->getNamedItem("class");
|
|
if (!(isset($classAttr) && $classAttr->nodeValue &&
|
|
preg_match('/(^|\s)skip-keywords($|\s)/', $classAttr->nodeValue) == 1))
|
|
{
|
|
$this->addKeywordLinksToDomNodes($node->childNodes, $dict, $doc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Source: http://78.47.251.156/svn/stern-consulting/sunstarPlugin/branches/1.4/lib/sun.class.php
|
|
*
|
|
* @param string $classes Space separated values for the "class"-attribute
|
|
* @return array
|
|
*/
|
|
private function getKeywordsToLinksDict($classes = '', $context = null)
|
|
{
|
|
if ($context)
|
|
{
|
|
if (!isset($this->dictByContext[$context]))
|
|
{
|
|
$this->dictByContext[$context] = null;
|
|
}
|
|
$dict = &$this->dictByContext[$context];
|
|
}
|
|
else
|
|
{
|
|
$dict = &$this->globalDict;
|
|
}
|
|
|
|
if($dict === null)
|
|
{
|
|
$dict = [];
|
|
/* $keywords = $this->entityManager->getRepository('AppBundle:Keyword')->findAll();
|
|
foreach($keywords as $keyword)
|
|
{
|
|
if(isset($dict[$keyword->getValue()]))
|
|
{
|
|
continue;
|
|
}
|
|
$dictEntry = $this->createKeywordDictEntry($keyword->getUrl(), $keyword->getValue(), $classes);
|
|
if ($dictEntry !== null)
|
|
{
|
|
$dict[$keyword->getValue()] = $dictEntry;
|
|
}
|
|
}
|
|
|
|
$pages = $this->entityManager->createQueryBuilder()
|
|
->from('AppBundle:Page', 'p')
|
|
->select('p')
|
|
->where('p.keyword IS NOT NULL')
|
|
->getQuery()
|
|
->execute()
|
|
;
|
|
foreach($pages as $page)
|
|
{
|
|
if(isset($dict[$page->getKeyword()]))
|
|
{
|
|
continue;
|
|
}
|
|
$dictEntry = $this->createKeywordDictEntry($page->getUrlPath(), $page->getKeyword(), $classes);
|
|
if ($dictEntry !== null)
|
|
{
|
|
$dict[$page->getKeyword()] = $dictEntry;
|
|
}
|
|
}
|
|
*/
|
|
/** @var Page $page */
|
|
$keywords = Util::loadFromApi('cms/keywords', ['url'=>'']);
|
|
foreach($keywords as $keyword => $url)
|
|
{
|
|
if(isset($dict[$keyword]))
|
|
{
|
|
continue;
|
|
}
|
|
$dictEntry = $this->createKeywordDictEntry("/".$url, $keyword, $classes);
|
|
if ($dictEntry !== null)
|
|
{
|
|
$dict[$keyword] = $dictEntry;
|
|
}
|
|
}
|
|
}
|
|
return $dict;
|
|
}
|
|
|
|
private function createKeywordDictEntry($url, $keywordValue, $classes)
|
|
{
|
|
$port = parse_url($url, PHP_URL_PORT);
|
|
if($url[0] == '/' || strtolower($_SERVER['HTTP_HOST']) ==
|
|
strtolower(parse_url($url, PHP_URL_HOST) .($port ? ':'. $port : '')))
|
|
{
|
|
// Same host => check if same page
|
|
$urlPath = parse_url($url, PHP_URL_PATH);
|
|
if($_SERVER['REQUEST_URI'] == $urlPath ||
|
|
($_SERVER['REQUEST_URI'] == '/' && $urlPath == ''))
|
|
{
|
|
// Yes => we don't want to link to the current URL
|
|
return null;
|
|
}
|
|
// No => setup a JS popup layer
|
|
$attr = '';
|
|
$additional_classes = 'intern-link show-layer ';
|
|
}
|
|
else
|
|
{
|
|
$additional_classes = '';
|
|
$attr = 'target="_blank"';
|
|
}
|
|
return '<a href="'. $url .'" '. $attr .' class="'. $additional_classes . $classes .'">'. $keywordValue .'</a>';
|
|
}
|
|
|
|
} |