src/Eccube/Controller/ContactController.php line 108

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Eccube\Controller;
  13. use Eccube\Controller\AbstractController;
  14. use Eccube\Entity\Customer;
  15. use Eccube\Event\EccubeEvents;
  16. use Eccube\Event\EventArgs;
  17. use Eccube\Form\Type\Front\ContactType;
  18. use Eccube\Repository\PageRepository;
  19. use Eccube\Service\MailService;
  20. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  21. use Symfony\Component\Filesystem\Filesystem;
  22. use Symfony\Component\Form\Extension\Core\Type\CollectionType;
  23. use Symfony\Component\Form\Extension\Core\Type\FileType;
  24. use Symfony\Component\Form\Extension\Core\Type\HiddenType;
  25. use Symfony\Component\Form\FormBuilderInterface;
  26. use Symfony\Component\HttpFoundation\File\File;
  27. use Symfony\Component\HttpFoundation\Request;
  28. use Symfony\Component\HttpFoundation\Response;
  29. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  30. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  31. use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
  32. use Symfony\Component\Routing\Annotation\Route;
  33. class ContactController extends AbstractController
  34. {
  35.     /**
  36.      * @var MailService
  37.      */
  38.     protected $mailService;
  39.     /**
  40.      * @var PageRepository
  41.      */
  42.     private $pageRepository;
  43.     const ROUTE_SHOWROOM 'showroom_confirm';
  44.     const ROUTE_CATALOG 'catalog_confirm';
  45.     const ROUTE_OTHER 'other_confirm';
  46.     const ROUTE_COORDINATE 'coordinate_confirm';
  47.     const ROUTE_CONTACT 'contact';
  48.     const MODE_FORM 'form';
  49.     const MODE_COMPLETE 'complete';
  50.     const SHOWROOM_RESERVED_GINZA '銀座ショールーム予約';
  51.     const SHOWROOM_RESERVED_YOKOHAMA '横浜ショールーム予約';
  52.     /**
  53.      * ContactController constructor.
  54.      *
  55.      * @param MailService $mailService
  56.      * @param PageRepository $pageRepository
  57.      */
  58.     public function __construct(
  59.         MailService $mailService,
  60.         PageRepository $pageRepository)
  61.     {
  62.         $this->mailService $mailService;
  63.         $this->pageRepository $pageRepository;
  64.     }
  65.     /**
  66.      * お問い合わせ選択画面.
  67.      *
  68.      * @Route("/contact", name="contact", methods={"GET", "POST"})
  69.      * @Template("Contact/index.twig")
  70.      */
  71.     public function selectType(Request $request)
  72.     {
  73.         return [];
  74.     }
  75.      /**
  76.      * お問い合わせ入力画面.
  77.      *
  78.      * @Route("/contact/showroom", name="showroom_confirm", methods={"GET", "POST"})
  79.      * @Route("/contact/catalog", name="catalog_confirm", methods={"GET", "POST"})
  80.      * @Route("/contact/other", name="other_confirm", methods={"GET", "POST"})
  81.      * @Route("/contact/coordinate", name="coordinate_confirm", methods={"GET", "POST"})
  82.      * @Template("Contact/form.twig")
  83.      */
  84.     public function index(Request $request)
  85.     {
  86.         $type $request->attributes->get('_route');
  87.         $mode $request->request->get('mode');
  88.         $builder $this->formFactory->createBuilder(ContactType::class, null, [
  89.             'type' => $type,
  90.         ]);
  91.         // コーディネートサービスだったら画像のフォームを追加
  92.         if ($type == self::ROUTE_COORDINATE){
  93.             $this->addCommonForms($builder);
  94.         };
  95.         $form $builder->getForm();
  96.         if ($this->isGranted('ROLE_USER')) {
  97.             /** @var Customer $user */
  98.             $user $this->getUser();
  99.             $form->setData([
  100.                 'name01' => $user->getName01(),
  101.                 'name02' => $user->getName02(),
  102.                 'kana01' => $user->getKana01(),
  103.                 'kana02' => $user->getKana02(),
  104.                 'postal_code' => $user->getPostalCode(),
  105.                 'pref' => $user->getPref(),
  106.                 'addr01' => $user->getAddr01(),
  107.                 'addr02' => $user->getAddr02(),
  108.                 'phoneDateType_number' => $user->getPhoneNumber(),
  109.                 'email' => $user->getEmail(),
  110.             ]);
  111.         }
  112.         $event = new EventArgs(['form' => $form], $request);
  113.         $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_CONTACT_INDEX_INITIALIZE);
  114.         $form->handleRequest($request);
  115.         if ($form->isSubmitted() && $form->isValid()) {
  116.             $images= [];
  117.                 if ($mode == self::MODE_FORM) {
  118.                     if ($type == self::ROUTE_COORDINATE){
  119.                         // 画像の登録
  120.                         $add_images $form->get('add_images')->getData();
  121.                         foreach ($add_images as $add_image) {
  122.                             // 移動
  123.                             $file = new File($this->eccubeConfig['eccube_temp_image_dir'] . '/' $add_image);
  124.                             // FIXME: リロードするとtemp_imageから移動している為、does not existエラーが生じる
  125.                             $file->move($this->eccubeConfig['eccube_save_image_dir'], $add_image);
  126.                         }
  127.                         // 画像の削除
  128.                         $delete_images $form->get('delete_images')->getData();
  129.                         $fs = new Filesystem();
  130.                         foreach ($delete_images as $delete_image) {
  131.                             $fs->remove($this->eccubeConfig['eccube_temp_image_dir'] . '/' $delete_image);
  132.                             $key array_search($delete_image$images);
  133.                             if ($key !== false) {
  134.                                 unset($images[$key]);
  135.                             }
  136.                         }
  137.                     }
  138.                     return $this->render('Contact/confirm.twig', [
  139.                         'form' => $form->createView(),
  140.                         'type' => $type,
  141.                     ]);
  142.                 } elseif ($mode == self::MODE_COMPLETE) {
  143.                     if ($type == self::ROUTE_COORDINATE){
  144.                         $add_images $form->get('add_images')->getData();
  145.                         foreach ($add_images as $add_image) {
  146.                             $images[] = $add_image;
  147.                         }
  148.                     }
  149.                     $data = [
  150.                         ...$form->getData(),
  151.                         'images' => $images,
  152.                     ];
  153.                     $data['contact_type'] = $type;
  154.                     $event = new EventArgs(['form' => $form'data' => $data], $request);
  155.                     $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_CONTACT_INDEX_COMPLETE);
  156.                     $data $event->getArgument('data');
  157.                     // 件名を動的に設定
  158.                     if ($type === self::ROUTE_OTHER) {
  159.                         $subject '[祈りの道具屋まなか] お問い合わせを受け付けました';
  160.                     } elseif ($type === self::ROUTE_CATALOG) {
  161.                         $subject '[祈りの道具屋まなか] カタログの請求を受け付けました';
  162.                     } elseif ($type === self::ROUTE_COORDINATE) {
  163.                         $subject '[祈りの道具屋まなか] コーディネートサービスのお申込みを受け付けました';
  164.                     } elseif ($type === self::ROUTE_SHOWROOM && $data['which_showroom'] === self::SHOWROOM_RESERVED_GINZA) {
  165.                         $subject '[祈りの道具屋まなか] 銀座ショールームのご予約希望日を受け付けました';
  166.                     } elseif ($type === self::ROUTE_SHOWROOM && $data['which_showroom'] === self::SHOWROOM_RESERVED_YOKOHAMA) {
  167.                         $subject '[祈りの道具屋まなか] 横浜ショールームのご予約希望日を受け付けました';
  168.                     }
  169.                     // メール送信
  170.                     $this->mailService->sendContactMail($data$subject);
  171.                     return $this->redirectToRoute('contact_complete');
  172.                 }
  173.         }
  174.         return [
  175.             'form' => $form->createView(),
  176.             'type' => $type,
  177.         ];
  178.     }
  179.     /**
  180.      * お問い合わせ完了画面.
  181.      *
  182.      * @Route("/contact/complete", name="contact_complete", methods={"GET"})
  183.      * @Template("Contact/complete.twig")
  184.      */
  185.     public function complete()
  186.     {
  187.         return [];
  188.     }
  189.       /**
  190.      * 各フォームに共通するフォームを追加.
  191.      */
  192.     private function addCommonForms(FormBuilderInterface $builder)
  193.     {
  194.         // 画像関連
  195.         $builder
  196.             ->add('coordinate_image'FileType::class, [
  197.                 'multiple' => true,
  198.                 'required' => false,
  199.                 'mapped' => false,
  200.             ])
  201.             ->add('images'CollectionType::class, [
  202.                 'entry_type' => HiddenType::class,
  203.                 'required' => false,
  204.                 'prototype' => true,
  205.                 'mapped' => false,
  206.                 'allow_add' => true,
  207.                 'allow_delete' => true,
  208.             ])
  209.             ->add('add_images'CollectionType::class, [
  210.                 'entry_type' => HiddenType::class,
  211.                 'required' => false,
  212.                 'prototype' => true,
  213.                 'mapped' => false,
  214.                 'allow_add' => true,
  215.                 'allow_delete' => true,
  216.             ])
  217.             ->add('delete_images'CollectionType::class, [
  218.                 'entry_type' => HiddenType::class,
  219.                 'required' => false,
  220.                 'prototype' => true,
  221.                 'mapped' => false,
  222.                 'allow_add' => true,
  223.                 'allow_delete' => true,
  224.             ]);
  225.     }
  226.     /**
  227.      * 画像アップロード時にリクエストされるメソッド.
  228.      *
  229.      * @see https://pqina.nl/filepond/docs/api/server/#process
  230.      * @Route("/coordinate/image/process", name="coordinate_image_process", methods={"POST"})
  231.      */
  232.     public function imageProcess(Request $request)
  233.     {
  234.         if (!$request->isXmlHttpRequest() && $this->isTokenValid()) {
  235.             throw new BadRequestHttpException();
  236.         }
  237.         $form_id $request->get('id');
  238.         $images $request->files->get($form_id);
  239.         $allowExtensions = ['gif''jpg''jpeg''png'];
  240.         $files = [];
  241.         if (count($images) > 0) {
  242.             foreach ($images as $img) {
  243.                 foreach ($img as $image) {
  244.                     // ファイルフォーマット検証
  245.                     $mimeType $image->getMimeType();
  246.                     if (!== strpos($mimeType'image')) {
  247.                         throw new UnsupportedMediaTypeHttpException();
  248.                     }
  249.                     // 拡張子
  250.                     $extension $image->getClientOriginalExtension();
  251.                     if (!in_array(strtolower($extension), $allowExtensions)) {
  252.                         throw new UnsupportedMediaTypeHttpException();
  253.                     }
  254.                     $filename date('mdHis') . uniqid('_') . '.' $extension;
  255.                     $image->move($this->eccubeConfig['eccube_temp_image_dir'], $filename);
  256.                     $files[] = $filename;
  257.                 }
  258.             }
  259.         }
  260.         return new Response(array_shift($files));
  261.     }
  262.     /**
  263.      * アップロード画像を取得する際にコールされるメソッド.
  264.      *
  265.      * @see https://pqina.nl/filepond/docs/api/server/#load
  266.      * @Route("/coordinate/image/load", name="coordinate_image_load", methods={"GET"})
  267.      */
  268.     public function imageLoad(Request $request)
  269.     {
  270.         if (!$request->isXmlHttpRequest()) {
  271.             throw new BadRequestHttpException();
  272.         }
  273.         $dirs = [
  274.             $this->eccubeConfig['eccube_save_image_dir'],
  275.             $this->eccubeConfig['eccube_temp_image_dir'],
  276.         ];
  277.         foreach ($dirs as $dir) {
  278.             if (strpos($request->query->get('source'), '..') !== false) {
  279.                 throw new NotFoundHttpException();
  280.             }
  281.             $image \realpath($dir '/' $request->query->get('source'));
  282.             $dir \realpath($dir);
  283.             if (\is_file($image) && \str_starts_with($image$dir)) {
  284.                 $file = new \SplFileObject($image);
  285.                 return $this->file($file$file->getBasename());
  286.             }
  287.         }
  288.         throw new NotFoundHttpException();
  289.     }
  290.     /**
  291.      * アップロード画像をすぐ削除する際にコールされるメソッド.
  292.      *
  293.      * @see https://pqina.nl/filepond/docs/api/server/#revert
  294.      * @Route("/coordinate/image/revert", name="coordinate_image_revert", methods={"DELETE"})
  295.      */
  296.     public function imageRevert(Request $request)
  297.     {
  298.         if (!$request->isXmlHttpRequest() && $this->isTokenValid()) {
  299.             throw new BadRequestHttpException();
  300.         }
  301.         $tempFile $this->eccubeConfig['eccube_temp_image_dir'] . '/' $request->getContent();
  302.         if (is_file($tempFile) && stripos(realpath($tempFile), $this->eccubeConfig['eccube_temp_image_dir']) === 0) {
  303.             $fs = new Filesystem();
  304.             $fs->remove($tempFile);
  305.             return new Response(nullResponse::HTTP_NO_CONTENT);
  306.         }
  307.         throw new NotFoundHttpException();
  308.     }
  309. }