<?php
declare(strict_types=1);
namespace WebBundle\Service;
use DateTimeImmutable;
use FlexApp\Service\RedisCachePool;
use Google\Cloud\Core\Exception\GoogleException;
use Google\Cloud\Core\Exception\ServiceException;
use Psr\Cache\InvalidArgumentException;
use WebBundle\Client\GoogleTranslateClient;
use WebBundle\Constant\RedisKeysConstant;
use WebBundle\Helper\ArticleSettingsHelper;
use WebBundle\Repository\ArticleRepository;
use WebBundle\Repository\ReviewsCacheRepository;
class GoogleTranslateService
{
// отключить кеш - поставить в false
private const ENABLE_CACHE = true;
private GoogleTranslateClient $googleTranslateClient;
private RedisCachePool $redisCachePool;
private ArticleRepository $articleRepository;
private ReviewsCacheRepository $reviewsCacheRepository;
public function __construct(
GoogleTranslateClient $googleTranslateClient,
RedisCachePool $redisCachePool,
ArticleRepository $articleRepository,
ReviewsCacheRepository $reviewsCacheRepository
) {
$this->googleTranslateClient = $googleTranslateClient;
$this->redisCachePool = $redisCachePool;
$this->articleRepository = $articleRepository;
$this->reviewsCacheRepository = $reviewsCacheRepository;
}
public function translateCommentForArticle(int $id, string $toLang): array
{
$toLang = strtolower($toLang);
$redisCacheKey = RedisKeysConstant::COMMENT_TRANSLATE . $id . $toLang;
if (self::ENABLE_CACHE && $data = $this->iHaveRedisDataByNameSpaceAndKey($redisCacheKey)) {
return (array) $data;
}
// ищем в репке
$article = $this->articleRepository->find($id);
if (null === $article) {
return $this->prepareResponse(null, null, 'Cant find article');
}
// если запрашиваемый язык перевода есть у арт и не пустой
$method = 'getDescription' . ucfirst($toLang);
if (method_exists($article, $method)) {
if ($article->$method() !== null) {
$content = (string) $article->$method();
// необходимо постОбработать контент на предмет наличия ссылок
$content = ArticleSettingsHelper::replaceLinkToReal($content, $this->articleRepository);
$contentForResponse = $this->prepareResponse($content, false);
$this->setContentToRedis($redisCacheKey, $contentForResponse, RedisKeysConstant::COMMENT_TRANSLATE()->expire());
return $contentForResponse;
}
}
// переводить будем с английского
$content = $article->getDescriptionEn();
if (empty($content)) {
return $this->prepareResponse(null, null, 'Haven\'t eng description');
}
// необходимо предОбработать контент на предмет наличия ссылок
$content = ArticleSettingsHelper::replaceLinkToReal($content, $this->articleRepository);
// запросим перевод у гугла
$translateData = $this->translate($content, $toLang);
if (null === $translateData) {
return $this->prepareResponse('', true);
}
$translateResponse = $this->prepareResponse($translateData, true);
$this->setContentToRedis($redisCacheKey, $translateResponse, RedisKeysConstant::COMMENT_TRANSLATE()->expire());
return $translateResponse;
}
public function translateReviewAboutService(int $id, string $toLang): array
{
$toLang = strtolower($toLang);
$redisCacheKey = RedisKeysConstant::REVIEW_ABOUT_SERVICE . $id . $toLang;
if (self::ENABLE_CACHE && $data = $this->iHaveRedisDataByNameSpaceAndKey($redisCacheKey)) {
return (array) $data;
}
// ищем в репке
$review = $this->reviewsCacheRepository->getReview($id);
if (null === $review) {
return $this->prepareResponse(null, null, 'Cant find review');
}
// если отзыв на запрашиваемом языке
$content = $review->getContent();
if (strtolower($review->getLanguage()) === $toLang) {
$contentForResponse = $this->prepareResponse($content, false);
$this->setContentToRedis($redisCacheKey, $contentForResponse, RedisKeysConstant::REVIEW_ABOUT_SERVICE()->expire());
return $contentForResponse;
}
if (empty($content)) {
return $this->prepareResponse(null, null, 'Empty review');
}
// запросим перевод у гугла
$translateData = $this->translate($content, $toLang);
if (null === $translateData) {
return $this->prepareResponse('', true);
}
$translateResponse = $this->prepareResponse($translateData, true);
$this->setContentToRedis($redisCacheKey, $translateResponse, RedisKeysConstant::REVIEW_ABOUT_SERVICE()->expire());
return $translateResponse;
}
/**
* Получаем данные из редиса, если есть по ключу $pool массив и содержит ключ $redisCacheKey
*
* @param string $redisCacheKey
* @return mixed|null
*/
private function iHaveRedisDataByNameSpaceAndKey(string $redisCacheKey)
{
try {
if ($redisCacheItem = $this->redisCachePool->getPool()->getItem($redisCacheKey)) {
return $redisCacheItem->get();
}
} catch (InvalidArgumentException $e) {
return null;
}
return null;
}
private function setContentToRedis(string $redisCacheKey, $content, ?DateTimeImmutable $expire): void
{
$pool = $this->redisCachePool->getPool();
try {
$item = $pool->getItem($redisCacheKey);
} catch (InvalidArgumentException $e) {
return;
}
$item->expiresAt($expire);
$item->set($content);
$pool->save($item);
}
private function translate(string $content, string $toLang): ?string
{
return $this->translateAndGetFullArray($content, $toLang)['text'] ?? null;
}
private function translateAndGetFullArray(string $content, string $toLang): ?array
{
try {
return $this->googleTranslateClient->translate($content, $toLang);
} catch (ServiceException|GoogleException $e) {
return null;
}
}
private function prepareResponse(?string $content, ?bool $isGoogleTranslate = null, ?string $error = null): array
{
$response = [];
if (null !== $content) {
$response['content'] = $content;
}
if (null !== $isGoogleTranslate) {
$response['translatedByGoogle'] = $isGoogleTranslate;
}
if (null !== $error) {
$response['error'] = $error;
}
return $response;
}
}