<?php
namespace App\Controller\Api;
use App\Entity\Institution;
use App\Entity\Dish;
use App\Entity\Wine;
use App\Entity\WineColor;
use App\Entity\Grape;
use App\Entity\Beer;
use App\Entity\BeerColor;
use App\Entity\Drink;
use App\Entity\Menu;
use App\Entity\Allergen;
use App\Entity\Label;
use App\Entity\LocaleFront;
use App\Entity\InstitutionReview;
use App\Entity\InstitutionReviewSummary;
use App\Entity\Contest;
use App\Entity\ContestEntry;
use App\Entity\ContestTicket;
use App\Service\MobileAppSerializeService;
use App\Service\ProductTranslationService;
use DateInterval;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Common\Collections\Criteria;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Class MizogooMobileController
* @package App\Controller\Api
* @Route(path="/api/mobile/app/", name="api_mobile_app_")
*/
class MobileAppController extends AbstractController
{
private EntityManagerInterface $em;
private MobileAppSerializeService $mobileAppSerializeService;
private ProductTranslationService $productTranslationService;
private TranslatorInterface $translator;
public function __construct(
EntityManagerInterface $em,
MobileAppSerializeService $mobileAppSerializeService,
ProductTranslationService $productTranslationService,
TranslatorInterface $translator
) {
$this->em = $em;
$this->mobileAppSerializeService = $mobileAppSerializeService;
$this->productTranslationService = $productTranslationService;
$this->translator = $translator;
}
/**
* @param Institution $institution
* @return JsonResponse
* @Route("supported-data-languages/{institution}", name="getSupportedDataLanguages", requirements={"institution"="\d+"})
*/
public function getSupportedDataLanguages(Institution $institution)
{
return new JsonResponse([
'success' => true,
'supportedDataLanguages' => $this->mobileAppSerializeService->serializeSupportedDataLanguages($institution),
]);
}
/**
* @param Institution $institution
* @return JsonResponse
* @Route("institution/functionalities/{institution}", name="getFunctionalities", requirements={"institution"="\d+"})
*/
public function getFunctionalities(Institution $institution)
{
return new JsonResponse([
'success' => true,
'functionalities' => $this->mobileAppSerializeService->serializeFunctionalities($institution),
]);
}
/**
* @param Institution $institution
* @return JsonResponse
* @Route("institution/personalization/{institution}", name="getInstitutionPersonalization", requirements={"institution"="\d+"})
* @Route("{language}/institution/personalization/{institution}", name="getInstitutionPersonalizationLanguage", requirements={"institution"="\d+"})
*/
public function getInstitutionPersonalization(Institution $institution)
{
return new JsonResponse([
'success' => true,
'institutionPersonalization' => $this->mobileAppSerializeService->serializeInstitutionPersonalization($institution),
]);
}
/**
* @param string|null $language
* @param Institution $institution
* @return JsonResponse
* @Route("institution/overview/{institution}", name="getInstitutionOverview", requirements={"institution"="\d+"})
* @Route("{language}/institution/overview/{institution}", name="getInstitutionOverviewLanguage", requirements={"institution"="\d+"})
*/
public function getInstitutionOverview(Institution $institution, ?string $language = null): JsonResponse
{
if ($institution->isActive() && $institution->getUser()->isActive()) {
// And if the translation should be updated automatically when an item has been altered
$updateTranslationIfAltered = true;
foreach ($institution->getInstitutionLocaleFronts() as $institutionLocaleFront) {
if (strcmp($institutionLocaleFront->getLocaleFront()->getTag(), $language) === 0) {
$updateTranslationIfAltered = false;
break;
}
}
/** @var LocaleFront $localeFront */
$localeFront = $this->em->getRepository(LocaleFront::class)->findOneBy(array('tag' => $language));
// Retrieve default institutionLocaleFront
$institutionLocaleFronts = $institution->getInstitutionLocaleFronts();
$defaultInstitutionLocaleFrontCriteria = Criteria::create()
->where(Criteria::expr()->eq('isDefault', true));
$defaultInstitutionLocaleFront = $institutionLocaleFronts->matching($defaultInstitutionLocaleFrontCriteria)->first()->getLocaleFront();
if ($localeFront) {
// Default locale front criteria (used to check if the item has already been translated or not)
$defaultLocaleElementTranslationCriteria = Criteria::create()
->where(Criteria::expr()->eq('localeFront', $defaultInstitutionLocaleFront));
// Requested locale front criteria (used to check if the item has already been translated or not)
$currentLocaleElementTranslationCriteria = Criteria::create()
->where(Criteria::expr()->eq('localeFront', $localeFront));
// Going throw every products
foreach ($institution->getDishes() as $dish) {
// Retrieve the original translation
$defaultDishTranslation = $dish->getDishTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
// Try to retrieve the translated item
$alreadyTranslatedItem = $dish->getDishTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
// Check if this item has already been translated in the required language
if (!$alreadyTranslatedItem) {
// If not, translate it and create a new 'translation item'
$this->productTranslationService->translateDish($dish, $defaultDishTranslation, null, $localeFront);
} else {
// But even if the translation exists, it's not enough, we have to make sure that the 'orginal' dish has not been altered
// To do so, we check whether the 'updated' timestamp of the requested translation is earlier than the one of the original language
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultDishTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
// Update translation
$this->productTranslationService->translateDish($dish, $defaultDishTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
foreach ($institution->getDishCategories() as $dishCategory) {
$defaultDishCategoryTranslation = $dishCategory->getDishCategoryTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $dishCategory->getDishCategoryTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateDishCategory($dishCategory, $defaultDishCategoryTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultDishCategoryTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateDishCategory($dishCategory, $defaultDishCategoryTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
$allergens = $this->em->getRepository(Allergen::class)->findAll();
foreach ($allergens as $allergen) {
$defaultAllergenTranslation = $allergen->getAllergenTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $allergen->getAllergenTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateAllergen($allergen, $defaultAllergenTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultAllergenTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateAllergen($allergen, $defaultAllergenTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
$labels = $this->em->getRepository(Label::class)->findAll();
foreach ($labels as $label) {
$defaultLabelTranslation = $label->getLabelTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $label->getLabelTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateLabel($label, $defaultLabelTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultLabelTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateLabel($label, $defaultLabelTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
foreach ($institution->getWines() as $wine) {
$defaultWineTranslation = $wine->getWineTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $wine->getWineTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateWine($wine, $defaultWineTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultWineTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateWine($wine, $defaultWineTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
foreach ($institution->getWineCategories() as $wineCategory) {
$defaultWineCategoryTranslation = $wineCategory->getWineCategoryTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $wineCategory->getWineCategoryTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateWineCategory($wineCategory, $defaultWineCategoryTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultWineCategoryTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateWineCategory($wineCategory, $defaultWineCategoryTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
$wineColors = $this->em->getRepository(WineColor::class)->findAll();
foreach ($wineColors as $wineColor) {
$defaultWineColorTranslation = $wineColor->getWineColorTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $wineColor->getWineColorTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateWineColor($wineColor, $defaultWineColorTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultWineColorTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateWineColor($wineColor, $defaultWineColorTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
$criteria = Criteria::create()
->where(Criteria::expr()->eq('institution', null))
->orWhere(Criteria::expr()->eq('institution', $institution));
$grapes = $this->em->getRepository(Grape::class)->matching($criteria);
foreach ($grapes as $grape) {
$defaultGrapeTranslation = $grape->getGrapeTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $grape->getGrapeTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateGrape($grape, $defaultGrapeTranslation, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultGrapeTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateGrape($grape, $defaultGrapeTranslation, $localeFront);
}
}
}
foreach ($institution->getBeers() as $beer) {
$defaultBeerTranslation = $beer->getBeerTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $beer->getBeerTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateBeer($beer, $defaultBeerTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultBeerTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateBeer($beer, $defaultBeerTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
foreach ($institution->getBeerCategories() as $beerCategory) {
$defaultBeerCategoryTranslation = $beerCategory->getBeerCategoryTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $beerCategory->getBeerCategoryTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateBeerCategory($beerCategory, $defaultBeerCategoryTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultBeerCategoryTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateBeerCategory($beerCategory, $defaultBeerCategoryTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
$beerColors = $this->em->getRepository(BeerColor::class)->findAll();
foreach ($beerColors as $beerColor) {
$defaultBeerColorTranslation = $beerColor->getBeerColorTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $beerColor->getBeerColorTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateBeerColor($beerColor, $defaultBeerColorTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultBeerColorTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateBeerColor($beerColor, $defaultBeerColorTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
foreach ($institution->getDrinks() as $drink) {
$defaultDrinkTranslation = $drink->getDrinkTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $drink->getDrinkTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateDrink($drink, $defaultDrinkTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultDrinkTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateDrink($drink, $defaultDrinkTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
foreach ($institution->getDrinkCategories() as $drinkCategory) {
$defaultDrinkCategoryTranslation = $drinkCategory->getDrinkCategoryTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $drinkCategory->getDrinkCategoryTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateDrinkCategory($drinkCategory, $defaultDrinkCategoryTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultDrinkCategoryTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateDrinkCategory($drinkCategory, $defaultDrinkCategoryTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
foreach ($institution->getMenus() as $menu) {
$defaultMenuTranslation = $menu->getMenuTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $menu->getMenuTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateMenu($menu, $defaultMenuTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultMenuTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateMenu($menu, $defaultMenuTranslation, $alreadyTranslatedItem, $localeFront);
}
}
foreach ($menu->getInnerCategories() as $menuInnerCategory) {
$defaultMenuInnerCategoryTranslation = $menuInnerCategory->getMenuInnerCategoryTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $menuInnerCategory->getMenuInnerCategoryTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateMenuInnerCategory($menuInnerCategory, $defaultMenuInnerCategoryTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultMenuInnerCategoryTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateMenuInnerCategory($menuInnerCategory, $defaultMenuInnerCategoryTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
}
foreach ($institution->getMenuCategories() as $menuCategory) {
$defaultMenuCategoryTranslation = $menuCategory->getMenuCategoryTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $menuCategory->getMenuCategoryTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateMenuCategory($menuCategory, $defaultMenuCategoryTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultMenuCategoryTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateMenuCategory($menuCategory, $defaultMenuCategoryTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
foreach ($institution->getOffers() as $offer) {
foreach ($offer->getOfferDishes() as $offerDish) {
$defaultOfferDishTranslation = $offerDish->getOfferDishTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $offerDish->getOfferDishTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if ($defaultOfferDishTranslation) {
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateOfferDish($offerDish, $defaultOfferDishTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultOfferDishTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateOfferDish($offerDish, $defaultOfferDishTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
}
foreach ($offer->getOfferWines() as $offerWine) {
$defaultOfferWineTranslation = $offerWine->getOfferWineTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $offerWine->getOfferWineTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if ($defaultOfferWineTranslation) {
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateOfferWine($offerWine, $defaultOfferWineTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultOfferWineTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateOfferWine($offerWine, $defaultOfferWineTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
}
foreach ($offer->getOfferBeers() as $offerBeer) {
$defaultOfferBeerTranslation = $offerBeer->getOfferBeerTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $offerBeer->getOfferBeerTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if ($defaultOfferBeerTranslation) {
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateOfferBeer($offerBeer, $defaultOfferBeerTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultOfferBeerTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateOfferBeer($offerBeer, $defaultOfferBeerTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
}
foreach ($offer->getOfferDrinks() as $offerDrink) {
$defaultOfferDrinkTranslation = $offerDrink->getOfferDrinkTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $offerDrink->getOfferDrinkTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if ($defaultOfferDrinkTranslation) {
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateOfferDrink($offerDrink, $defaultOfferDrinkTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultOfferDrinkTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateOfferDrink($offerDrink, $defaultOfferDrinkTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
}
foreach ($offer->getOfferMenus() as $offerMenu) {
$defaultOfferMenuTranslation = $offerMenu->getOfferMenuTranslations()->matching($defaultLocaleElementTranslationCriteria)->first();
$alreadyTranslatedItem = $offerMenu->getOfferMenuTranslations()->matching($currentLocaleElementTranslationCriteria)->first();
if ($defaultOfferMenuTranslation) {
if (!$alreadyTranslatedItem) {
$this->productTranslationService->translateOfferMenu($offerMenu, $defaultOfferMenuTranslation, null, $localeFront);
} else {
if ($alreadyTranslatedItem->getUpdatedAt() < $defaultOfferMenuTranslation->getUpdatedAt() && $updateTranslationIfAltered) {
$this->productTranslationService->translateOfferMenu($offerMenu, $defaultOfferMenuTranslation, $alreadyTranslatedItem, $localeFront);
}
}
}
}
}
// No corresponding LocaleFront get the one by default
} else {
$language = $defaultInstitutionLocaleFront->getTag();
}
return new JsonResponse([
'success' => true,
'institution' => $this->mobileAppSerializeService->serializeInstitutionOverview($institution, $language),
]);
}
return new JsonResponse([
'success' => false,
'message' => $this->translator->trans('institutionHome.notFound'),
]);
}
/**
* @param Institution $institution
* @return JsonResponse
* @Route("institution/{institution}", name="getInstitutionDetail", requirements={"institution"="\d+"})
*/
public function getInstitutionDetail(Institution $institution): JsonResponse
{
return new JsonResponse([
'success' => true,
'institution' => $this->mobileAppSerializeService->serializeInstitution($institution),
]);
}
/**
* @param Dish $dish
* @param string|null $language
* @return JsonResponse
* @Route("dish/{dish}", name="getDishDetail", requirements={"dish"="\d+"})
* @Route("{language}/dish/{dish}", name="getDishDetailLanguage", requirements={"dish"="\d+"})
*/
public function getDishDetail(Dish $dish, ?string $language = null): JsonResponse
{
if (is_null($language)) {
$institutionLocaleFronts = $dish->getInstitution()->getInstitutionLocaleFronts();
$defaultInstitutionLocaleFrontCriteria = Criteria::create()
->where(Criteria::expr()->eq('isDefault', true));
$language = $institutionLocaleFronts->matching($defaultInstitutionLocaleFrontCriteria)->first()->getLocaleFront()->getTag();
}
return new JsonResponse([
'success' => true,
'dish' => $this->mobileAppSerializeService->serializeDish($dish, $language),
]);
}
/**
* @param Wine $wine
* @param string|null $language
* @return JsonResponse
* @Route("wine/{wine}", name="getWineDetail", requirements={"wine"="\d+"})
* @Route("{language}/wine/{wine}", name="getWineDetailLanguage", requirements={"wine"="\d+"})
*/
public function getWineDetail(Wine $wine, ?string $language = null): JsonResponse
{
if (is_null($language)) {
$institutionLocaleFronts = $wine->getInstitution()->getInstitutionLocaleFronts();
$defaultInstitutionLocaleFrontCriteria = Criteria::create()
->where(Criteria::expr()->eq('isDefault', true));
$language = $institutionLocaleFronts->matching($defaultInstitutionLocaleFrontCriteria)->first()->getLocaleFront()->getTag();
}
return new JsonResponse([
'success' => true,
'wine' => $this->mobileAppSerializeService->serializeWine($wine, $language),
]);
}
/**
* @param Beer $beer
* @param string|null $language
* @return JsonResponse
* @Route("beer/{beer}", name="getBeerDetail", requirements={"beer"="\d+"})
* @Route("{language}/beer/{beer}", name="getBeerDetailLanguage", requirements={"beer"="\d+"})
*/
public function getBeerDetail(Beer $beer, ?string $language = null): JsonResponse
{
if (is_null($language)) {
$institutionLocaleFronts = $beer->getInstitution()->getInstitutionLocaleFronts();
$defaultInstitutionLocaleFrontCriteria = Criteria::create()
->where(Criteria::expr()->eq('isDefault', true));
$language = $institutionLocaleFronts->matching($defaultInstitutionLocaleFrontCriteria)->first()->getLocaleFront()->getTag();
}
return new JsonResponse([
'success' => true,
'beer' => $this->mobileAppSerializeService->serializeBeer($beer, $language),
]);
}
/**
* @param Drink $drink
* @param string|null $language
* @return JsonResponse
* @Route("drink/{drink}", name="getDrinkDetail", requirements={"drink"="\d+"})
* @Route("{language}/drink/{drink}", name="getDrinkDetailLanguage", requirements={"drink"="\d+"})
*/
public function getDrinkDetail(Drink $drink, ?string $language = null): JsonResponse
{
if (is_null($language)) {
$institutionLocaleFronts = $drink->getInstitution()->getInstitutionLocaleFronts();
$defaultInstitutionLocaleFrontCriteria = Criteria::create()
->where(Criteria::expr()->eq('isDefault', true));
$language = $institutionLocaleFronts->matching($defaultInstitutionLocaleFrontCriteria)->first()->getLocaleFront()->getTag();
}
return new JsonResponse([
'success' => true,
'drink' => $this->mobileAppSerializeService->serializeDrink($drink, $language),
]);
}
/**
* @param Menu $menu
* @param string|null $language
* @return JsonResponse
* @Route("menu/{menu}", name="getMenuDetail", requirements={"menu"="\d+"})
* @Route("{language}/menu/{menu}", name="getMenuDetailLanguage", requirements={"menu"="\d+"})
*/
public function getMenuDetail(Menu $menu, ?string $language = null): JsonResponse
{
if (is_null($language)) {
$institutionLocaleFronts = $menu->getInstitution()->getInstitutionLocaleFronts();
$defaultInstitutionLocaleFrontCriteria = Criteria::create()
->where(Criteria::expr()->eq('isDefault', true));
$language = $institutionLocaleFronts->matching($defaultInstitutionLocaleFrontCriteria)->first()->getLocaleFront()->getTag();
}
return new JsonResponse([
'success' => true,
'menu' => $this->mobileAppSerializeService->serializeMenu($menu, $language),
]);
}
/**
* @param Request $request
* @param string|null $language
* @return JsonResponse|void
* @Route("paired-wines", name="getPairedWines")
* @Route("{language}/paired-wines", name="getPairedWinesLanguage")
*/
public function getPairedWines(Request $request, ?string $language = null)
{
// Retrieve the parameters (the list of selected dishes id)
$data = json_decode($request->getContent(), true);
$dishesId = $data['dishesId'] ?? null;
$selectedDishes = $data['selectedDishes'] ?? null;
// The final pairing list that will be return in the end (Json serialized format)
$winePairings = [];
$dishes = [];
if (!is_null($dishesId) || !is_null($selectedDishes)) {
$pairings = [];
if (!is_null($dishesId)) {
// Find dishes by ID list
$dishes = $this->em->getRepository(Dish::class)->findBy(['id' => $dishesId]);
} elseif (!is_null($selectedDishes)) {
// Extract IDs from selectedDishes
$dishIds = array_column($selectedDishes, 'id');
$dishes = $this->em->getRepository(Dish::class)->findBy(['id' => $dishIds]);
}
// Get every selected dishes
foreach ($dishes as $dish) {
// Determine quantity (default 1 if not provided)
if ($selectedDishes) {
$sel = array_filter($selectedDishes, fn($s) => $s['id'] == $dish->getId());
$qty = $sel ? (int)reset($sel)['quantity'] : 1;
} else {
$qty = 1;
}
// For each of them, get the associated wines
foreach ($dish->getWinePairings() as $winePairing) {
$alreadyInsidePairings = false;
// Check if the wine is already in the list
foreach ($pairings as $pairing) {
// If the wine is already in the list, increase the matching count
$currentPairingId = $pairing->getWine()->getId();
if ($currentPairingId == $winePairing->getWine()->getId()) {
$alreadyInsidePairings = true;
// Increase the matching value considering quantity
$pairing->setValue($pairing->getValue() + ($winePairing->getValue() * $qty));
break;
}
}
// If not already in the list, add it (with quantity applied)
if (!$alreadyInsidePairings) {
$winePairing->setValue($winePairing->getValue() * $qty);
$pairings[] = $winePairing;
}
}
}
// Serialize pairings
foreach ($pairings as $pairing) {
$serializedWinePairing = $this->mobileAppSerializeService->serializeWinePairing($pairing, false, true, $language);
if (!is_null($serializedWinePairing)) {
$winePairings[] = $serializedWinePairing;
}
}
// Sort paired wines by value (best to worst)
usort($winePairings, function ($item1, $item2) {
return $item1['value'] <= $item2['value'];
});
return new JsonResponse([
'success' => true,
'winePairings' => $winePairings,
]);
}
return new JsonResponse([
'success' => true,
'winePairings' => [],
]);
}
/**
* @param Request $request
* @param string|null $language
* @return JsonResponse|void
* @Route("paired-beers", name="getPairedBeers")
* @Route("{language}/paired-beers", name="getPairedBeersLanguage")
*/
public function getPairedBeers(Request $request, ?string $language = null)
{
// Retrieve the parameters (the list of selected dishes id)
$data = $request->getContent();
$data = json_decode($data, true);
$dishesId = $data['dishesId'];
// The final pairing list that will be return in the end (Json serialized format)
$beerPairings = [];
if (!is_null($dishesId)) {
$pairings = [];
// Get every selected dishes
foreach ($dishesId as $dishId) {
$dish = $this->em->getRepository(Dish::class)->find($dishId);
// For each of them, get the associated beers
foreach ($dish->getBeerPairings() as $beerPairing) {
// Check if the wine is already in the list
$alreadyInsidePairings = false;
foreach ($pairings as $pairing) {
// If the beer is already in the list, increase the matching count
$currentPairingId = $pairing->getBeer()->getId();
if ($currentPairingId == $beerPairing->getBeer()->getId()) {
$alreadyInsidePairings = true;
$pairing->setValue($pairing->getValue() + $beerPairing->getValue());
break;
}
}
// Else, if the beer is not already in the list, we need to add it
if (!$alreadyInsidePairings) {
$pairings[] = $beerPairing;
}
}
}
// Serialize pairings
foreach ($pairings as $pairing) {
$serializedBeerPairing = $this->mobileAppSerializeService->serializeBeerPairing($pairing, false, true, $language);
if (!is_null($serializedBeerPairing)) {
$beerPairings[] = $serializedBeerPairing;
}
}
// Sort paired wines by value (best to worst)
usort($beerPairings, function ($item1, $item2) {
return $item1['value'] <= $item2['value'];
});
return new JsonResponse([
'success' => true,
'beerPairings' => $beerPairings,
]);
}
}
/**
* @param Request $request
* @return JsonResponse
* @Route("institution-review", name="getInstitutionReview")
*/
public function getInstitutionReview(Request $request): JsonResponse
{
$data = $request->getContent();
$data = json_decode($data, true);
$institutionId = $data['restaurantId'];
$userAppId = $data['userAppId'];
$institution = $this->em->getRepository(Institution::class)->find($institutionId);
$institutionReviews = $institution->getInstitutionReviews();
$criteria = Criteria::create()
->where(Criteria::expr()->eq('userAppId', $userAppId));
$userReview = $institutionReviews->matching($criteria)->first();
if (!$userReview) {
return new JsonResponse([
'success' => false,
]);
}
return new JsonResponse([
'success' => true,
'institutionReview' => $this->mobileAppSerializeService->serializeInstitutionReview($userReview),
]);
}
/**
* @param Request $request
* @return JsonResponse
* @Route("institution-review/create", name="setInstitutionReview")
*/
public function setInstitutionReview(Request $request): JsonResponse
{
// Retrieve the review (contains appUserId, restaurantId, rating and comments)
$data = $request->getContent();
$data = json_decode($data, true);
$review = $data['review'];
if (!is_null($review)) {
$institution = $this->em->getRepository(Institution::class)->find($review['restaurantId']);
$institutionReviews = $institution->getInstitutionReviews();
$criteria = Criteria::create()
->where(Criteria::expr()->eq('userAppId', $review['userAppId']));
$userReview = $institutionReviews->matching($criteria)->first();
$institutionReview = null;
$reviewTotalNumber = count($institutionReviews);
$institutionReviewSummary = $institution->getInstitutionReviewSummary();
if ($institution) {
// Update the review if this user already rate this institution
if ($userReview) {
$previousRating = $userReview->getRating();
if ($reviewTotalNumber > 1) {
// Calculate the total score (average * number of reviews)
$totalScore = $institutionReviewSummary->getAverageReviewScore() * $reviewTotalNumber;
$totalScore = $totalScore - $previousRating + $review['rating'];
$average = $totalScore / $reviewTotalNumber;
} else {
// Special case: there was only one review → the average simply becomes the new score
$average = $review['rating'];
}
$institutionReviewSummary->setAverageReviewScore($average);
// Decrement the previous counter
$this->decrementStarCount($institutionReviewSummary, $previousRating);
// Increment the new counter
$this->incrementStarCount($institutionReviewSummary, $review['rating']);
$this->em->persist($institutionReviewSummary);
$userReview->setRating($review['rating']);
$userReview->setComments($review['comments'] ?: null);
$userReview->setDate(new DateTime());
$this->em->persist($userReview);
$this->em->flush();
return new JsonResponse([
'success' => true,
'institutionReview' => $this->mobileAppSerializeService->serializeInstitutionReview($userReview),
]);
// Or create a new InstitutionReview otherwise
} else {
if (!$institutionReviewSummary) {
$institutionReviewSummary = new InstitutionReviewSummary();
$institutionReviewSummary->setAverageReviewScore($review['rating']);
$institutionReviewSummary->setOneStarNumber(0);
$institutionReviewSummary->setTwoStarNumber(0);
$institutionReviewSummary->setThreeStarNumber(0);
$institutionReviewSummary->setFourStarNumber(0);
$institutionReviewSummary->setFiveStarNumber(0);
$institutionReviewSummary->setInstitution($institution);
} else {
$averageScore = $institutionReviewSummary->getAverageReviewScore();
$newAverage = $averageScore + (($review['rating'] - $averageScore) / ($reviewTotalNumber + 1));
$institutionReviewSummary->setAverageReviewScore($newAverage);
}
$this->incrementStarCount($institutionReviewSummary, $review['rating']);
$this->em->persist($institutionReviewSummary);
$institutionReview = new InstitutionReview();
$institutionReview->setUserAppId($review['userAppId']);
$institutionReview->setRating($review['rating']);
$institutionReview->setComments($review['comments'] ?: null);
$institutionReview->setInstitution($institution);
$institutionReview->setDate(new DateTime());
$this->em->persist($institutionReview);
$this->em->flush();
return new JsonResponse([
'success' => true,
'institutionReview' => $this->mobileAppSerializeService->serializeInstitutionReview($institutionReview),
]);
}
} else {
return new JsonResponse([
'success' => false,
]);
}
} else {
return new JsonResponse([
'success' => false,
]);
}
}
private function incrementStarCount(InstitutionReviewSummary $summary, int $rating): void
{
switch ($rating) {
case 1: $summary->setOneStarNumber($summary->getOneStarNumber() + 1); break;
case 2: $summary->setTwoStarNumber($summary->getTwoStarNumber() + 1); break;
case 3: $summary->setThreeStarNumber($summary->getThreeStarNumber() + 1); break;
case 4: $summary->setFourStarNumber($summary->getFourStarNumber() + 1); break;
case 5: $summary->setFiveStarNumber($summary->getFiveStarNumber() + 1); break;
}
}
private function decrementStarCount(InstitutionReviewSummary $summary, int $rating): void
{
switch ($rating) {
case 1: $summary->setOneStarNumber($summary->getOneStarNumber() - 1); break;
case 2: $summary->setTwoStarNumber($summary->getTwoStarNumber() - 1); break;
case 3: $summary->setThreeStarNumber($summary->getThreeStarNumber() - 1); break;
case 4: $summary->setFourStarNumber($summary->getFourStarNumber() - 1); break;
case 5: $summary->setFiveStarNumber($summary->getFiveStarNumber() - 1); break;
}
}
/**
* @param Institution $institution
* @param Request $request
* @return JsonResponse
* @Route("contest/tickets/{institution}", name="getTickets", requirements={"institution"="\d+"}))
*/
public function getTickets(Institution $institution, Request $request): JsonResponse
{
$data = $request->getContent();
$data = json_decode($data, true);
$userAppId = $data['userAppId'];
if (is_null($userAppId)) {
return new JsonResponse([
'success' => false,
]);
}
$userAppTickets = [];
$contests = $institution->getContests();
foreach ($contests as $contest) {
$criteria = Criteria::create()
->where(Criteria::expr()->eq('userAppId', $userAppId));
$contestTickets = $contest->getContestTickets()->matching($criteria);
foreach ($contestTickets as $ticket) {
$userAppTickets[] = $this->mobileAppSerializeService->serializeTicket($ticket);
}
}
return new JsonResponse([
'success' => true,
'tickets' => $userAppTickets,
]);
}
/**
* @param Contest $contest
* @param Request $request
* @return JsonResponse
* @throws \Exception
* @Route("contest/draw/{contest}", name="draw", requirements={"contest"="\d+"}))
*/
public function draw(Contest $contest, Request $request): JsonResponse
{
$data = $request->getContent();
$data = json_decode($data, true);
$userAppId = $data['userAppId'];
if (is_null($userAppId)) {
return new JsonResponse([
'success' => false,
]);
}
$now = date_create();
$entryLimitTime = $contest->getEntryLimitTime();
//on vérifie si l'utilisateur n'a pas déjà participé dans la période maximum
$criteria = Criteria::create()
->where(Criteria::expr()->eq('userAppId', $userAppId))
->orderBy(array('enterAt' => Criteria::DESC));
/** @var ContestEntry $contestEntry */
$contestEntry = $contest->getContestEntries()->matching($criteria)->first();
//si l'utilisateur a déjà participé
if ($contestEntry) {
//on vérifie si l'utilisateur peut participer à nouveau
$nextTicketDateTime = clone $contestEntry->getEnterAt();
$nextTicketDateTime->add(new DateInterval('PT' . $entryLimitTime . 'S'));
if ($now < $nextTicketDateTime) {
return new JsonResponse([
'success' => false,
'message' => "mobile user already got an entry on that period",
]);
}
}
//on ajoute une nouvelle participation au jeu concours
$contestEntry = new ContestEntry();
$contestEntry->setEnterAt($now);
$contestEntry->setContest($contest);
$contestEntry->setUserAppId($userAppId);
$this->em->persist($contestEntry);
//on vérifie si il existe un instant gagnant à cet instant
$criteria = Criteria::create()
->where(Criteria::expr()->lte('instantWinDate', $now))
->andWhere(Criteria::expr()->eq('isWon', false));
/** @var ContestTicket $contestTicket */
$contestTicket = $contest->getContestTickets()->matching($criteria)->first();
//si le ticket gagnant existe, on l'associe à l'utilisateur
if ($contestTicket) {
$contestTicket->setUserAppId($userAppId);
$contestTicket->setIsWon(true);
$contestTicket->setWonAt($now);
$this->em->persist($contestTicket);
$this->em->flush();
return new JsonResponse([
'success' => true,
'ticket' => $this->mobileAppSerializeService->serializeTicket($contestTicket)
]);
}
//sinon le ticket est perdant
else {
$this->em->flush();
return new JsonResponse([
'success' => true,
'ticket' => false
]);
}
}
/**
* @param Institution $institution
* @param Request $request
* @return JsonResponse
* @throws \Exception
* @Route("contest/access/{institution}", name="getAccess", requirements={"institution"="\d+"}))
*/
public function getAccess(Institution $institution, Request $request): JsonResponse
{
$data = $request->getContent();
$data = json_decode($data, true);
$userAppId = $data['userAppId'];
if (is_null($userAppId)) {
return new JsonResponse([
'success' => false,
]);
}
$now = date_create();
//on récupère le premier jeu concours valide à cette date du restaurant /!\ 1 seul jeu concours possible pour la période donnée
$criteria = Criteria::create()
->where(Criteria::expr()->lte('startDate', $now))
->andWhere(Criteria::expr()->gte('endDate', $now))
->andWhere(Criteria::expr()->eq('isPlaying', true));
/** @var Contest $contest */
$contest = $institution->getContests()->matching($criteria)->first();
if (!$contest) {
//pas de jeux concours en cours
return new JsonResponse([
'success' => true,
'access' => [
'hasAccess' => false,
'nextTicketTime' => null
]
]);
}
$entryLimitTime = $contest->getEntryLimitTime();
//on vérifie si l'utilisateur n'a pas déjà participé dans la période maximum
$criteria = Criteria::create()
->where(Criteria::expr()->eq('userAppId', $userAppId))
->orderBy(array('enterAt' => Criteria::DESC));
/** @var ContestEntry $contestEntry */
$contestEntry = $contest->getContestEntries()->matching($criteria)->first();
//si l'utilisateur a déjà participé
if ($contestEntry) {
//on vérifie si l'utilisateur a le droit à une nouvelle participation
$nextTicketDateTime = clone $contestEntry->getEnterAt();
$nextTicketDateTime->add(new DateInterval('PT' . $entryLimitTime . 'S'));
if ($now > $nextTicketDateTime) {
//participation disponible
return new JsonResponse([
'success' => true,
'contestId' => $contest->getId(),
'access' => [
'hasAccess' => true,
'nextTicketTime' => null,
'type' => $contest->getType()
]
]);
} else {
//tirage indisponible pour le moment
return new JsonResponse([
'success' => true,
'contestId' => $contest->getId(),
'access' => [
'hasAccess' => false,
'nextTicketTime' => date_diff($nextTicketDateTime, $now),
'type' => $contest->getType()
]
]);
}
} else {
//tirage disponible
return new JsonResponse([
'success' => true,
'contestId' => $contest->getId(),
'access' => [
'hasAccess' => true,
'nextTicketTime' => null,
'type' => $contest->getType()
]
]);
}
}
/**
* @param Contest $contest
* @return JsonResponse
* @Route("contest/{contest}", name="getContest", requirements={"contest"="\d+"}))
*/
public function getContest(Contest $contest): JsonResponse
{
return new JsonResponse([
'success' => true,
'contest' => $this->mobileAppSerializeService->serializeContest($contest)
]);
}
}