<?php
/**
* (c) 2018 - Biloba IT Balleyer & Lohrmann GbR
* All Rights reserved
*
* Contact: Biloba IT <kontakt@biloba-it.de>
*/
namespace Biloba\IntlTranslation\Components\TextProcessors;
use Psr\Log\LoggerInterface;
use Biloba\IntlTranslation\Struct\TranslationContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
class Links extends AbstractTextProcessor {
private $container;
/**
* @var SystemConfigService
*/
private $systemConfigService;
/**
* @var LoggerInterface
*/
private $log;
private $config;
public function __construct($container = null, $systemConfigService = null, LoggerInterface $log) {
$this->container = $container;
$this->systemConfigService = $systemConfigService;
$this->log = $log;
$this->config = $this->systemConfigService->get('BilobaIntlTranslation.config');
}
/**
* Tries to find a appropriate translation for a given url. If no alternative link is found, returns null.
*
* @param $url string The original url
* @param $to string The translation target language in ISO format
* @return string|null
*/
protected function getLinkAlternative($url, $to) {
$this->log->debug('Get alternative link for ' . $url . ' ' . $to);
//setup curl
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_URL => $url
]);
//exec curl & store the response
$response = curl_exec($ch);
$info = curl_getinfo($ch);
$parameter = explode('?', $url);
if(count($parameter) == 2) {
$parameter = '?' . $parameter[1];
}
else {
$parameter = '';
}
//check if the request was successfull
if($info['http_code'] == 200) {
//get all link tags from the result html page
preg_match_all('/<link ([^>]+)>/i', $response, $linkTags);
foreach($linkTags[0] as $index=>$full) {
//get all tag attributes & clean them
preg_match_all('/([a-z\-]+)=("([^"]+)"|\'([^\']+)\')/i', strtolower($linkTags[1][$index]), $matches);
foreach($matches[1] as $j=>$key) {
$attributes[$key] = trim(rtrim(isset($matches[3][$j]) ? $matches[3][$j] : $matches[2][$j]));
}
//check if all required attributes are set for this link
if(isset($attributes['rel'], $attributes['hreflang'], $attributes['href'])) {
// alternative iso check
$aryTo = explode('-', $to);
//check if the current link matches the required lanuage
if($attributes['rel'] == 'alternate' && strpos($attributes['hreflang'], strtolower($to)) === 0) {
$this->log->debug('Found alternative link for ' . $url . ' => ' . $attributes['href']);
return $attributes['href'] . $parameter;
}
elseif(sizeof($aryTo) > 0 && $attributes['rel'] == 'alternate' && strpos($attributes['hreflang'], strtolower($aryTo[0])) === 0) {
$this->log->debug('Found alternative link for ' . $url . ' => ' . $attributes['href']);
return $attributes['href'] . $parameter;
}
}
}
} else {
$this->log->debug('Request to ' . $url . ' failed!', $info);
}
return null;
}
/**
* Translates all link hrefs. Checks the <link rel="alternate" ...> tags of the link target. If nothing is set
* the original target is preserved.
*
* @param $text string The text that is translated
* @param $to string The translation target language in ISO format
* @return string
*/
protected function translateLinks($text, $to) {
return preg_replace_callback('/href=("([^"]+)"|\'([^\']+)\')/i', function($match) use($to) {
$this->log->debug("Found link " . $match[0]);
//check if we should use double qoutes
$doubleQuotes = false;
if(strpos($match[1], '"') === 0) {
$doubleQuotes = true;
}
//get the url from the match
$url = (isset($match[3]) && $match[3] != "") ? $match[3] : $match[2];
//check if its a relative url
$parsedUrl = parse_url($url);
if(!isset($parsedUrl['host'])) {
$url = $this->convertRelativUrl($url);
}
//fetch alternative url
$alternate = $this->getLinkAlternative($url, $to);
//return the translated href attribute
if($doubleQuotes) {
return 'href="' . ($alternate ? $alternate : $url) . '"';
} else {
return 'href=\'' . ($alternate ? $alternate : $url) . '\'';
}
}, $text);
}
/**
* Converts /this/is/a/url to http://host/this/is/a/url
*
* @param $url string The Url to convert
* @return string
*/
protected function convertRelativUrl($url) {
$matchedUrl = null;
$shopId = $this->config['DefaultSalesChannel'];
$salesChannelRepository = $this->container->get('sales_channel.repository');
$criteria = new Criteria([$shopId]);
$criteria->addAssociation('domains');
$salesChannel = $salesChannelRepository->search($criteria, Context::createDefaultContext())->get($shopId);
$httpsPrefix = "https";
foreach($salesChannel->getDomains()->getElements() as $key=>$domain) {
// checking if url starts with https
if(str_starts_with($domain->getUrl(), $httpsPrefix)) {
// match http and https urls
preg_match('/^(https?):\/\/[^\s\/$.?#0-9].[^\s]*$/', $domain->getUrl(), $matches);
// fetch match at index 0, so we can get the full url
$matchedUrl = $matches[0];
}
}
return $matchedUrl . $url;
}
public function postTranslate(TranslationContext $context, string $text) :string {
if($text == null) {
return '';
}
// load plugin config
$config = $this->config['TranslateLinks'];
// only run processor if enabled
if(!$config){
return $text;
}
// only run processor if given value is html
if(!$this->hasTextHtml($text)) {
return $text;
}
return $this->translateLinks($text, $context->getTargetLanguage()->getLocale()->getCode());
}
}