<?php
declare(strict_types=1);
namespace Econsor\Amity\Services\AmityPosts;
use Econsor\Amity\Models\AmityPostLikes\AmityPostLikesEntity;
use Econsor\Amity\Services\Helpers\AmityRepositoryHelper;
use Econsor\Amity\Services\Stream\StreamProcessor;
use Econsor\Amity\Services\Stream\StreamSorter;
use Econsor\Amity\Services\Stream\StreamUtilities;
use Exception;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Econsor\Amity\Services\AmityPosts\LocalPostService;
use Shopware\Core\Content\Product\Aggregate\ProductMedia\ProductMediaCollection;
/**
* Class AmityPostService
* @package Econsor\Amity\Services\AmityPosts
*/
class AmityPostService
{
const STREAM_LIMIT = 100;
const STREAM_OFFSET = 10;
public function __construct(
protected StreamProcessor $streamProcessor,
protected StreamSorter $streamSorter,
protected StreamUtilities $utilities,
protected AmityRepositoryHelper $repositoryHelper,
protected LocalPostService $localPostService
) {}
/**
* @throws Exception
*/
public function fetchCustomerStats(string $customerId, SalesChannelContext $context): array
{
return [
'totalLikes' => $this->repositoryHelper->queryLikes($this->streamProcessor->getCriteriaLikeCount($customerId), $context->getContext())->count(),
'totalFollowers' => $this->repositoryHelper->queryFollowed($this->streamProcessor->getFollowing($customerId), $context->getContext())->count(),
'totalFollowings' => $this->repositoryHelper->queryFollowed($this->streamProcessor->getFollowed($customerId), $context->getContext())->count(),
'isFollowed' => $this->repositoryHelper->queryFollowed($this->streamProcessor->getFollowing($customerId)->addFilter(new EqualsFilter('customerId', $context->getCustomerId())), $context->getContext())->count() > 0,
'postCount' => $this->repositoryHelper->queryTotalPost($this->streamProcessor->getCriteriaPostCount($customerId), $context->getContext())->count(),
];
}
/**
* @throws Exception
*/
public function fetchStream(
?string $customerId,
SalesChannelContext $context,
string $mode = 'tags', // tags|liked|uploaded
?string $productId = null,
?string $postId = null,
$page = 1,
$limit = 100
): array {
$customerTags = !empty($customerId) ? $this->utilities->getCustomerTags($customerId, $context->getContext())?->get('tags')?->getElements() : [];
if (empty($customerTags)) {
$customerTags = $this->utilities->getAllTags($context->getContext())->getElements();
}
$result = match ($mode) {
'tags' => $this->buildNormalStream($customerTags, $customerId, $context, $productId, $postId, $page, $limit),
'liked' => !empty($customerId) ? $this->buildLikedStream($customerTags, $customerId, $context) : [],
'uploaded' => !empty($customerId) ? $this->buildUploadedStream($customerTags, $customerId, $context) : [],
'saved' => !empty($customerId) ? $this->buildSavedStream($customerTags, $customerId, $context) : [],
'details' => !empty($productId) ? $this->buildDetailStream($productId, $customerId, $context) : [],
default => throw new Exception('Stream Mode not recognized - try "tags", "details", "liked" or "uploaded"'),
};
$likedPostIds = [];
$savedPostIds = [];
$followedIds = [];
if (!empty($customerId)) {
foreach ($this->repositoryHelper->queryLikes($this->streamProcessor->getCriteriaLiked($customerId, 499), $context->getContext())->getIterator() as $like) {
/** @var AmityPostLikesEntity $like */
$likedPostIds[] = $like->getPostId();
}
foreach ($this->repositoryHelper->querySaved($this->streamProcessor->getSaved($customerId, 499), $context->getContext())->getIterator() as $saved) {
$savedPostIds[] = $saved->getPostId();
}
foreach ($this->repositoryHelper->queryFollowed($this->streamProcessor->getFollowed($customerId), $context->getContext())->getIterator() as $followed) {
$followedIds[] = $followed->followerId;
}
}
foreach ($result as &$post) {
/** @var AmityPostLikesEntity $post */
$post->addArrayExtension('stats', [
'liked' => in_array($post->getId(), $likedPostIds),
'saved' => in_array($post->getId(), $savedPostIds),
'followed' => in_array($post->postUser, $followedIds),
]);
$post = $this->convertVideoKey($post);
}
return $result;
}
public function buildNormalStream($customerTags, ?string $customerId, SalesChannelContext $context, ?string $productId = null, ?string $postId = null, $page = 1, $limit): array
{
$viewedVideos = !empty($customerId) ? $this->utilities->getViewedVideos($customerId, $context->getContext()) : [];
$viewedResults = $restResults = $latest = null;
$mainResults = $this->repositoryHelper->queryPosts2(
$this->streamProcessor->getCriteriaMain($customerTags, $viewedVideos, $limit, $productId, $customerId),
$context,
$postId,
$page,
);
// /*
// * If the total Stream amount doesn't reach the 100 video cap, add videos from viewed.
// */
// if(($total = $mainResults->getTotal()) < $limit)
// {
// $limit = $limit - $total;
//
// $viewedResults = $this->repositoryHelper->queryPosts2(
// $this->streamProcessor->getCriteriaViewed($viewedVideos, $limit),
// $context,
// false,
// !empty($productId),
// );
//
// /*
// * If the total Stream amount STILL doesn't reach the 100 video cap, add videos from all tags.
// */
// if(($total += $viewedResults->getTotal()) < $limit)
// {
// /*
// * Update for not duplicate videos
// */
// $viewedIds = [];
// foreach ($viewedResults as $result)
// {
// $viewedIds[] = $result->getId();
// }
// $limit = $limit - $total;
//
// $restResults = $this->repositoryHelper->queryPosts2(
// $this->streamProcessor->getCriteriaRest($customerTags, $viewedIds, 100),
// $context,
// false,
// !empty($productId),
// );
// $restResults = $restResults->slice(0, 2);
// }
//
// $latest = $viewedResults->first();
// }
//
// // Get the latest watched video
// if(!$latest && !empty($customerId))
// {
// $latest = $this->getLatestViewed($customerId, $context);
// }
//
// if(!empty($productId))
// {
// $latest = null;
// }
return $this->streamSorter->sort(
$this->grabWeights($customerTags, $customerId, $context),
$mainResults,
$viewedResults,
$restResults,
$latest
);
}
public function buildUploadedStream($customerTags, string $customerId, SalesChannelContext $context): array
{
return $this->streamSorter->sort(
$this->grabWeights($customerTags, $customerId, $context),
// $this->repositoryHelper->queryPosts2($this->streamProcessor->getUploadedCriteria($customerId, 499), $context, null, 1, 'uploaded')
$this->repositoryHelper->queryPosts($this->streamProcessor->getUploadedCriteria($customerId, 499), $context, true)
);
}
public function buildLikedStream($customerTags, string $customerId, SalesChannelContext $context): array
{
$ids = [];
foreach ($this->repositoryHelper->queryLikes($this->streamProcessor->getCriteriaLiked($customerId, 499), $context->getContext())->getIterator() as $like) {
/** @var AmityPostLikesEntity $like */
$ids[] = $like->getPostId();
}
if (empty($ids)) {
return [];
}
return $this->streamSorter->sort(
$this->grabWeights($customerTags, $customerId, $context),
$this->repositoryHelper->queryPosts2($this->streamProcessor->getIdCriteria($ids, 100, $customerId), $context, null, 1, 'liked')
);
}
public function buildSavedStream($customerTags, string $customerId, SalesChannelContext $context): array
{
$ids = [];
foreach ($this->repositoryHelper->querySaved($this->streamProcessor->getSaved($customerId, 499), $context->getContext())->getIterator() as $saved) {
/** @var AmityPostLikesEntity $saved */
$ids[] = $saved->getPostId();
}
if (empty($ids)) {
return [];
}
return $this->streamSorter->sort(
$this->grabWeights($customerTags, $customerId, $context),
$this->repositoryHelper->queryPosts2($this->streamProcessor->getIdCriteria($ids, 100, $customerId), $context, null, 1, 'saved')
);
}
public function getLatestViewed(string $customerId, SalesChannelContext $context)
{
$latest = $this->repositoryHelper->queryPosts(
$this->utilities->getLastViewedCriteria($customerId, $context->getContext()),
$context
);
return $latest->getTotal() ? $latest->first() : null;
}
public function grabWeights($customerTags, ?string $customerId, SalesChannelContext $context): array
{
return [
'viewTime' => !empty($customerId) ? $this->utilities->getViewTimeWeights($customerTags, $customerId, $context->getContext()) : null,
'orders' => !empty($customerId) ? $this->utilities->getOrderWeights($customerTags, $customerId, $context->getContext()) : null,
'social' => !empty($customerId) ? $this->utilities->getSocialGraphWeights($customerId, $context->getContext()) : null,
];
}
/**
* @param ProductEntity $product
* @param SalesChannelContext $context
* @param string|null $type
* @return array
*/
public function fetchPostsByEAN(ProductEntity $product, SalesChannelContext $context, ?string $type = null): array
{
$EANs = [$product->getEan()];
if (
array_key_exists('amityEANs', $product->getCustomFields())
&& $product->getCustomFields()['amityEANs']
) {
$EANs = array_merge($EANs, explode(',', $product->getCustomFields()['amityEANs']));
}
$filters = [];
foreach ($EANs as $EAN) {
$filters[] = (new EqualsFilter('ean', $EAN));
}
$criteria = (new Criteria())
->addFilter(new MultiFilter('OR', $filters))
->addAssociation('postChildren');
if ($type) {
$criteria->addFilter(new EqualsFilter('type', $type));
}
return $this->repositoryHelper->queryPosts(
$criteria,
$context
)->getElements();
}
public function buildDetailStream(string $productId, $customerId, SalesChannelContext $context): array
{
$ids = [];
foreach ($this->repositoryHelper->queryDetailPost($this->streamProcessor->getCriteriaDetail($productId, $customerId, 100), $context->getContext())->getIterator() as $post) {
$ids[] = $post->getId();
}
if (empty($ids)) {
return [];
}
return $this->streamSorter->sort(
$this->grabWeights([], $customerId, $context),
$this->repositoryHelper->queryPosts($this->streamProcessor->getIdCriteria($ids, 10, $customerId), $context, true)
);
}
public function convertVideoKey($post)
{
if (!empty($post->getCustomer())) {
if (!empty($post->getCustomer()?->getCustomFields())) {
$postCustomerCustomFields = $post->getCustomer()?->getCustomFields();
if (!empty($postCustomerCustomFields['emailListInvited'])) {
$postCustomerCustomFields['emailListInvited'] = [];
}
if (!empty($postCustomerCustomFields['emailsInvited'])) {
$postCustomerCustomFields['emailsInvited'] = [];
}
$post->getCustomer()?->setCustomFields($postCustomerCustomFields);
}
}
if (!empty($post->getProduct())) {
if (!empty($post->getProduct()?->getMedia())) {
$post->getProduct()?->setMedia(new ProductMediaCollection([]));
}
if (!empty($post->getProduct()?->getCustomFields())) {
$post->getProduct()?->setCustomFields([]);
}
if (!empty($post->getProduct()?->getTranslated())) {
$postProductCustomFields = $post->getProduct()?->getTranslated();
if (!empty($postProductCustomFields['customFields'])) {
$postProductCustomFields['customFields'] = [];
}
$post->getProduct()->setTranslated($postProductCustomFields);
}
}
if (!empty($post->getAmityObject())) {
$post->setAmityObject([]);
}
if (!empty($post->getPostChildren())) {
foreach ($post->getPostChildren() as $postChild) {
if (!empty($postChild->getAmityObject())) {
$postChild->setAmityObject([]);
}
if (!empty($postChild->getFile()) && !empty($postChild->getFile()->{'fileObject'})) {
$postChild->getFile()->{'fileObject'} = [];
}
}
}
return $post;
}
}