src/Controller/Api/ShopController.php line 184

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Api;
  3. use App\Component\ApiTrait;
  4. use App\Component\CartService;
  5. use App\Entity\Menu;
  6. use App\Entity\Order;
  7. use App\Entity\Shop;
  8. use App\Entity\ShopPlan;
  9. use App\Entity\User;
  10. use App\Form\Type\ApiCartAddItemType;
  11. use App\Form\Type\ApiCartEditItemType;
  12. use App\Form\Type\ApiContactType;
  13. use App\Form\Type\ApiShopFcmTokenType;
  14. use App\Form\Type\ApiShopRegisterType;
  15. use App\Form\Type\ApiShopSearchType;
  16. use App\Form\Type\ApiShopUpdateEstimatedMinutesType;
  17. use App\Form\Type\ApiShopUpdateHoursType;
  18. use App\Form\Type\ApiUpdateMenuStockType;
  19. use App\Form\Type\ApiUserFcmTokenType;
  20. use App\Form\Type\ApiUserRegisterVerifyType;
  21. use App\Form\Type\UserProfileType;
  22. use App\Form\Type\UserRegisterType;
  23. use App\Form\Type\UserRegisterVerifyType;
  24. use App\Security\OTPService;
  25. use Doctrine\DBAL\Exception\DeadlockException;
  26. use Doctrine\ORM\EntityManagerInterface;
  27. use Gesdinet\JWTRefreshTokenBundle\Model\RefreshTokenManagerInterface;
  28. use Illuminate\Http\JsonResponse;
  29. use Illuminate\Support\Js;
  30. use Knp\Component\Pager\PaginatorInterface;
  31. use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
  32. use Mailgun\Exception\HttpClientException;
  33. use Mailgun\Mailgun;
  34. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  35. use Symfony\Component\Form\Extension\Core\Type\FormType;
  36. use Symfony\Component\Form\FormError;
  37. use Symfony\Component\HttpFoundation\Request;
  38. use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
  39. use Symfony\Component\RateLimiter\RateLimiterFactory;
  40. use Symfony\Component\Routing\Annotation\Route;
  41. use Nelmio\ApiDocBundle\Annotation\Model;
  42. use OpenApi\Annotations as OA;
  43. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  44. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  45. use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
  46. use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
  47. use Symfony\Component\Serializer\Serializer;
  48. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  49. use function MongoDB\BSON\fromJSON;
  50. /**
  51.  * @OA\Tag(name="Shop")
  52.  */
  53. class ShopController extends AbstractController
  54. {
  55.     use ApiTrait;
  56.     /**
  57.      * @Route("/api/shop-register", name="api_shop_register", methods={"POST"})
  58.      * @see \App\Controller\IndexController::register()
  59.      * @OA\Response(
  60.      *     response=200,
  61.      *     description="店舗の掲載依頼を送信します。",
  62.      * )
  63.      * @OA\RequestBody(
  64.      *     @OA\MediaType(
  65.      *         mediaType="application-json",
  66.      *         @OA\Schema(ref=@Model(type=ApiShopRegisterType::class))
  67.      *     )
  68.      * )
  69.      * @OA\Post(summary="店舗掲載依頼", description="成功時、店舗登録し、完了メールをユーザーに送信します。")
  70.      * @OA\Tag(name="Shop")
  71.      * @return JsonResponse
  72.      */
  73.     public function shopRegister(EntityManagerInterface $emRequest $requestUserPasswordEncoderInterface $passwordEncoder)
  74.     {
  75. //        $user = $this->getUser();
  76.         $shop = new Shop();
  77.         $shop->setReady(false);
  78.         $form $this->createForm(ApiShopRegisterType::class, $shop, [
  79.             'csrf_protection' => false,
  80.         ]);
  81.         if ($request->getContent()) {
  82.             $data json_decode($request->getContent(), true);
  83.             $form->submit($data);
  84.         }
  85.         $form->handleRequest($request);
  86.         if ($form->isSubmitted()) {
  87.             if ($form->isValid()) {
  88.                 $data $form->getData();
  89.                 $shopPlan $em->getRepository('App:ShopPlan')->createQueryBuilder('sp')
  90.                     ->andWhere('sp.slug = :plan')
  91.                     ->setParameter('plan'ShopPlan::SLUG_STANDARD)
  92.                     ->setMaxResults(1)
  93.                     ->getQuery()
  94.                     ->getOneOrNullResult();
  95.                 $shop->setShopPlan($shopPlan);
  96.                 $shop->setPassword($passwordEncoder->encodePassword($shop$shop->getPlainPassword()));
  97.                 $em->persist($shop);
  98.                 $em->flush();
  99.                 try {
  100.                     $mailgun Mailgun::create($_ENV['MAILGUN_API_KEY']);
  101.                     $mailgun->messages()->send($_ENV['MAILGUN_DOMAIN'], array(
  102.                         'from'    => $_ENV['MAIL_FROM_ADDRESS'],
  103.                         'to'    => $shop->getEmail(),
  104.                         'bcc'  => $_ENV['MAIL_TO_ADDRESS'],
  105.                         'subject' => '掲載申し込み',
  106.                         //'text'    => $this->renderView('index/register.eml.twig', ['shop' => $shop])
  107.                         'template' => 'registration',
  108.                         'h:X-Mailgun-Variables' => json_encode([
  109.                             'url' => $this->generateUrl('shop_dashboard', [], UrlGeneratorInterface::ABSOLUTE_URL),
  110.                             'name' => $shop->getName(),
  111.                             'homepage' => 'https://uchideri.com'
  112.                         ])
  113.                     ));
  114.                 } catch (HttpClientException $e) {
  115.                 } catch (\Exception $e) {
  116.                 } catch (\Throwable $e) {
  117.                 }
  118.                 return new JsonResponse();
  119.             }
  120.         }
  121.         return $this->createValidationErrorJsonResponse($form);
  122.     }
  123.     /**
  124.      * @Route("/api/shop/update-fcm-token", name="api_shop_update_fcm_token", methods={"PATCH"})
  125.      * @OA\Response(
  126.      *     response=200,
  127.      *     description="",
  128.      * )
  129.      * @OA\RequestBody(
  130.      *     @OA\MediaType(
  131.      *         mediaType="application/json",
  132.      *         @OA\Schema(ref=@Model(type=ApiShopFcmTokenType::class))
  133.      *     )
  134.      * )
  135.      * @OA\Patch(summary="ユーザーFCMトークン更新", description="")
  136.      */
  137.     public function updateFcmToken(Request $requestEntityManagerInterface $em)
  138.     {
  139.         $user $this->getUser();
  140.         $form $this->createForm(ApiShopFcmTokenType::class, $user, [
  141.             'csrf_protection' => false,
  142.         ]);
  143.         if ($request->getContent()) {
  144.             $data json_decode($request->getContent(), true);
  145.             $form->submit($data);
  146.         }
  147.         $form->handleRequest($request);
  148.         if ($form->isSubmitted()) {
  149.             if ($form->isValid()) {
  150.                 $em->persist($user);
  151.                 $em->flush();
  152.             } else {
  153.                 return $this->createValidationErrorJsonResponse($form);
  154.             }
  155.         }
  156.         $serializer $this->container->get('serializer');
  157.         $em->refresh($user);
  158. //        $cart = $em->getRepository('App:Cart')->find($cart->getId());
  159.         return JsonResponse::fromJsonString($serializer->serialize($user'json'));
  160.     }
  161.     /**
  162.      * @Route("/api/shops", name="api_shops", methods={"GET"})
  163.      * @OA\Response(
  164.      *     response=200,
  165.      *     description="",
  166.      * )
  167.      * @OA\Get(summary="店舗一覧取得", description="店舗一覧取得を返します。")
  168.      * @OA\Tag(name="Shop")
  169.      */
  170.     public function shops(Request $requestEntityManagerInterface $emPaginatorInterface $paginator)
  171.     {
  172.         $builder $this->createShopListBuilder($em$request->get('area'), $request->get('location'), $request->get('categories'), $request->get('prepaid'), $request->get('delivery'), $request->get('onSale'));
  173.         $pagination $paginator->paginate($builder$request->get('page'1), 20);
  174.         $serializer $this->container->get('serializer');
  175.         $response JsonResponse::fromJsonString($serializer->serialize($pagination'json'));
  176.         $response->headers->set('Content-Type''application/json; charset=utf-8');
  177.         $response->headers->set('x-total-count'$pagination->getTotalItemCount());
  178.         return $response;
  179.     }
  180.     /**
  181.      * @Route("/api/shop/order-manager", name="api_shop_order_manager", methods={"GET"})
  182.      * @OA\Response(
  183.      *     response=200,
  184.      *     description="",
  185.      * )
  186.      * @OA\Get(summary="注文管理ページ表示", description="JWTを元にCookieベースのログイン状態にし、注文管理ページにリダイレクトします。")
  187.      */
  188.     public function toOrderManager(Request $requestEventDispatcherInterface $eventDispatcher)
  189.     {
  190.         $user $this->getUser();
  191.         // クッキーベースでログイン状態にする
  192.         $token = new UsernamePasswordToken($user'main'$user->getRoles());
  193.         $this->container->get('security.token_storage')->setToken($token);
  194.         $this->container->get('session')->set('_security_main'serialize($token));
  195.         $loginEvent = new InteractiveLoginEvent($request$token);
  196.         $eventDispatcher->dispatch($loginEvent'security.interactive_login');
  197.         return $this->redirectToRoute('shop_order_manager', ['app' => 1]);
  198.     }
  199.     /**
  200.      * @Route("/api/shop", name="api_shop_show", methods={"GET"})
  201.      * @OA\Response(
  202.      *     response=200,
  203.      *     description="",
  204.      * )
  205.      * @OA\Get(summary="店舗情報取得", description="自店舗情報を返します。")
  206.      * @OA\Tag(name="Shop")
  207.      */
  208.     public function index(Request $requestEventDispatcherInterface $eventDispatcher)
  209.     {
  210.         $shop $this->getUser();
  211.         $serializer $this->container->get('serializer');
  212.         return JsonResponse::fromJsonString($serializer->serialize($shop'json'));
  213.     }
  214.     /**
  215.      * @Route("/owner/api/menus", name="api_owner_menu", methods={"GET"})
  216.      * @OA\Response(
  217.      *     response=200,
  218.      *     description="",
  219.      * )
  220.      * @OA\Get(summary="メニュー一覧取得", description="自店舗のメニュー一覧を返します。")
  221.      * @OA\Tag(name="Shop")
  222.      */
  223.     public function menu(Request $requestEntityManagerInterface $emPaginatorInterface $paginator)
  224.     {
  225.         $shop $this->getUser();
  226.         $builder $em->getRepository('App:MenuGroup')->createQueryBuilder('mg')
  227.             ->leftJoin('mg.menus''m')
  228.             ->addSelect('m')
  229.             ->andWhere('mg.shop = :shop')
  230.             ->setParameter('shop'$shop)
  231.             ->orderBy('mg.position')
  232.             ->getQuery()
  233.         ;
  234.         $pagination $paginator->paginate($builder$request->get('page'1), 20);
  235.         $serializer $this->container->get('serializer');
  236.         return JsonResponse::fromJsonString($serializer->serialize($pagination'json'));
  237.     }
  238.     /**
  239.      * @Route("/api/shop-menus/{id}", name="api_shop_menu", methods={"GET"})
  240.      * @OA\Response(
  241.      *     response=200,
  242.      *     description="",
  243.      * )
  244.      * @OA\Get(summary="指定店舗のメニュー一覧取得", description="指定店舗のメニュー一覧を返します。")
  245.      * @OA\Tag(name="Shop")
  246.      */
  247.     public function shopMenus(Request $requestShop $shopEntityManagerInterface $emPaginatorInterface $paginator)
  248.     {
  249.         $builder $em->getRepository('App:MenuGroup')->createQueryBuilder('mg')
  250.             ->leftJoin('mg.menus''m')
  251.             ->addSelect('m')
  252.             ->andWhere('mg.shop = :shop')
  253.             ->setParameter('shop'$shop)
  254.             ->andWhere('m.shop = :shop')
  255.             ->setParameter('shop'$shop)
  256.             ->orderBy('mg.position')
  257.             ->getQuery()
  258.         ;
  259.         $pagination $paginator->paginate($builder$request->get('page'1), 20);
  260.         $serializer $this->container->get('serializer');
  261.         $response JsonResponse::fromJsonString($serializer->serialize($pagination'json'));
  262.         $response->headers->set('Content-Type''application/json; charset=utf-8');
  263.         return $response;
  264.     }
  265.     /**
  266.      * @Route("/owner/api/update-estimated-minutes", name="api_shop_update_estimated_minutes", methods={"POST"})
  267.      * @OA\Response(
  268.      *     response=200,
  269.      *     description="",
  270.      * )
  271.      * @OA\RequestBody(
  272.      *     @OA\MediaType(
  273.      *         mediaType="application-json",
  274.      *         @OA\Schema(ref=@Model(type=ApiShopUpdateEstimatedMinutesType::class))
  275.      *     )
  276.      * )
  277.      * @OA\Post(summary="待ち時間変更", description="")
  278.      * @OA\Tag(name="Shop")
  279.      */
  280.     public function updateEstimatedMinutes(Request $requestEntityManagerInterface $em)
  281.     {
  282.         /** @var Shop $shop */
  283.         $shop $this->getUser();
  284.         $form $this->createForm(ApiShopUpdateEstimatedMinutesType::class, $shop, [
  285.             'csrf_protection' => false,
  286.             '_block_prefix' => false,
  287.         ]);
  288.         $form->handleRequest($request);
  289.         if ($form->isSubmitted()) {
  290.             if ($form->isValid()) {
  291.                 $em->persist($shop);
  292.                 $em->flush();
  293.                 return new JsonResponse([
  294.                     'estimatedMinutes' => $shop->getAppEstimatedMinutes(),
  295.                 ]);
  296.             } else {
  297.                 return $this->createValidationErrorJsonResponse($form);
  298.             }
  299.         }
  300.         return new JsonResponse([], 422);
  301.     }
  302.     /**
  303.      * @Route("/owner/api/menu/{id}/update-stock", name="api_shop_menu_update_stock", methods={"POST"})
  304.      * @OA\Response(
  305.      *     response=200,
  306.      *     description="",
  307.      * )
  308.      * @OA\RequestBody(
  309.      *     @OA\MediaType(
  310.      *         mediaType="multipart/form-data",
  311.      *         @OA\Schema(ref=@Model(type=ApiUpdateMenuStockType::class))
  312.      *     )
  313.      * )
  314.      * @OA\Post(summary="メニューの在庫数変更", description="")
  315.      * @OA\Tag(name="Shop")
  316.      */
  317.     public function updateMenuStock(Request $requestMenu $menuEntityManagerInterface $em)
  318.     {
  319.         /** @var Shop $shop */
  320.         $shop $this->getUser();
  321.         if ($menu->getShop()->getId() != $shop->getId()) {
  322.             return new JsonResponse([], 403);
  323.         }
  324.         $form $this->createForm(ApiUpdateMenuStockType::class, $menu, [
  325.             'csrf_protection' => false,
  326.             '_block_prefix' => false,
  327.         ]);
  328.         $form->handleRequest($request);
  329.         if ($form->isSubmitted()) {
  330.             if ($form->isValid()) {
  331.                 try {
  332.                     $em->persist($menu);
  333.                     $em->flush();
  334.                 } catch (DeadlockException $e) {
  335.                     $MenuError = new FormError('他の処理と競合したため在庫数の更新を中止しました。''', [], null'menu');
  336.                     $form->addError($MenuError);
  337.                     return $this->createValidationErrorJsonResponse($form);
  338.                 }
  339.                 return new JsonResponse([
  340.                     'appStock' => $menu->getAppStock(),
  341.                 ]);
  342.             } else {
  343.                 return $this->createValidationErrorJsonResponse($form);
  344.             }
  345.         }
  346.         return new JsonResponse([], 422);
  347.     }
  348.     /**
  349.      * @Route("/owner/api/update-hours", name="api_shop_update_hours", methods={"POST"})
  350.      * @OA\Response(
  351.      *     response=200,
  352.      *     description="",
  353.      * )
  354.      * @OA\RequestBody(
  355.      *     @OA\MediaType(
  356.      *         mediaType="application-json",
  357.      *         @OA\Schema(ref=@Model(type=ApiShopUpdateHoursType::class))
  358.      *     )
  359.      * )
  360.      * @OA\Post(summary="受付時間変更", description="")
  361.      * @OA\Tag(name="Shop")
  362.      */
  363.     public function updateHours(Request $requestEntityManagerInterface $em)
  364.     {
  365.         /** @var Shop $shop */
  366.         $shop $this->getUser();
  367.         $form $this->createForm(ApiShopUpdateHoursType::class, $shop, [
  368.             'csrf_protection' => false,
  369.             '_block_prefix' => false,
  370.         ]);
  371.         $form->handleRequest($request);
  372.         if ($form->isSubmitted()) {
  373.             if ($form->isValid()) {
  374.                 $em->persist($shop);
  375.                 $em->flush();
  376.                 return new JsonResponse([
  377.                     'hourFrom' => $shop->getAppHourFrom()->format('H:i'),
  378.                     'hourTo' => $shop->getAppHourTo()->format('H:i'),
  379.                 ]);
  380.             } else {
  381.                 return $this->createValidationErrorJsonResponse($form);
  382.             }
  383.         }
  384.         return new JsonResponse([], 422);
  385.     }
  386.     /**
  387.      * @Route("/owner/api/closed", name="api_shop_closed", methods={"POST"})
  388.      * @OA\Response(
  389.      *     response=200,
  390.      *     description="",
  391.      * )
  392.      * @OA\Post(summary="受付終了", description="")
  393.      * @OA\Tag(name="Shop")
  394.      */
  395.     public function closed(Request $requestEntityManagerInterface $em)
  396.     {
  397.         /** @var Shop $shop */
  398.         $shop $this->getUser();
  399.         $shop->setAppClosed(true);
  400.         $em->persist($shop);
  401.         $em->flush();
  402.         return new JsonResponse();
  403.     }
  404.     /**
  405.      * @Route("/owner/api/open", name="api_shop_open", methods={"POST"})
  406.      * @OA\Response(
  407.      *     response=200,
  408.      *     description="",
  409.      * )
  410.      * @OA\Post(summary="受付再開", description="受付時間外の場合はクローズしたまま")
  411.      * @OA\Tag(name="Shop")
  412.      */
  413.     public function open(Request $requestEntityManagerInterface $em)
  414.     {
  415.         /** @var Shop $shop */
  416.         $shop $this->getUser();
  417.         $shop->setAppClosed(false);
  418.         $em->persist($shop);
  419.         $em->flush();
  420.         return new JsonResponse();
  421.     }
  422. }