sterntours/trunk/src/AppBundle/Service/KeywordService.php
2020-03-07 19:46:19 +01:00

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>';
}
}