<?php
/*
* This file is part of EC-CUBE
*
* Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
*
* http://www.ec-cube.co.jp/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Eccube\Controller;
use Eccube\Controller\AbstractController;
use Eccube\Entity\Customer;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Eccube\Form\Type\Front\ContactType;
use Eccube\Repository\PageRepository;
use Eccube\Service\MailService;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
use Symfony\Component\Routing\Annotation\Route;
class ContactController extends AbstractController
{
/**
* @var MailService
*/
protected $mailService;
/**
* @var PageRepository
*/
private $pageRepository;
const ROUTE_SHOWROOM = 'showroom_confirm';
const ROUTE_CATALOG = 'catalog_confirm';
const ROUTE_OTHER = 'other_confirm';
const ROUTE_COORDINATE = 'coordinate_confirm';
const ROUTE_CONTACT = 'contact';
const MODE_FORM = 'form';
const MODE_COMPLETE = 'complete';
const SHOWROOM_RESERVED_GINZA = '銀座ショールーム予約';
const SHOWROOM_RESERVED_YOKOHAMA = '横浜ショールーム予約';
/**
* ContactController constructor.
*
* @param MailService $mailService
* @param PageRepository $pageRepository
*/
public function __construct(
MailService $mailService,
PageRepository $pageRepository)
{
$this->mailService = $mailService;
$this->pageRepository = $pageRepository;
}
/**
* お問い合わせ選択画面.
*
* @Route("/contact", name="contact", methods={"GET", "POST"})
* @Template("Contact/index.twig")
*/
public function selectType(Request $request)
{
return [];
}
/**
* お問い合わせ入力画面.
*
* @Route("/contact/showroom", name="showroom_confirm", methods={"GET", "POST"})
* @Route("/contact/catalog", name="catalog_confirm", methods={"GET", "POST"})
* @Route("/contact/other", name="other_confirm", methods={"GET", "POST"})
* @Route("/contact/coordinate", name="coordinate_confirm", methods={"GET", "POST"})
* @Template("Contact/form.twig")
*/
public function index(Request $request)
{
$type = $request->attributes->get('_route');
$mode = $request->request->get('mode');
$builder = $this->formFactory->createBuilder(ContactType::class, null, [
'type' => $type,
]);
// コーディネートサービスだったら画像のフォームを追加
if ($type == self::ROUTE_COORDINATE){
$this->addCommonForms($builder);
};
$form = $builder->getForm();
if ($this->isGranted('ROLE_USER')) {
/** @var Customer $user */
$user = $this->getUser();
$form->setData([
'name01' => $user->getName01(),
'name02' => $user->getName02(),
'kana01' => $user->getKana01(),
'kana02' => $user->getKana02(),
'postal_code' => $user->getPostalCode(),
'pref' => $user->getPref(),
'addr01' => $user->getAddr01(),
'addr02' => $user->getAddr02(),
'phoneDateType_number' => $user->getPhoneNumber(),
'email' => $user->getEmail(),
]);
}
$event = new EventArgs(['form' => $form], $request);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_CONTACT_INDEX_INITIALIZE);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$images= [];
if ($mode == self::MODE_FORM) {
if ($type == self::ROUTE_COORDINATE){
// 画像の登録
$add_images = $form->get('add_images')->getData();
foreach ($add_images as $add_image) {
// 移動
$file = new File($this->eccubeConfig['eccube_temp_image_dir'] . '/' . $add_image);
// FIXME: リロードするとtemp_imageから移動している為、does not existエラーが生じる
$file->move($this->eccubeConfig['eccube_save_image_dir'], $add_image);
}
// 画像の削除
$delete_images = $form->get('delete_images')->getData();
$fs = new Filesystem();
foreach ($delete_images as $delete_image) {
$fs->remove($this->eccubeConfig['eccube_temp_image_dir'] . '/' . $delete_image);
$key = array_search($delete_image, $images);
if ($key !== false) {
unset($images[$key]);
}
}
}
return $this->render('Contact/confirm.twig', [
'form' => $form->createView(),
'type' => $type,
]);
} elseif ($mode == self::MODE_COMPLETE) {
if ($type == self::ROUTE_COORDINATE){
$add_images = $form->get('add_images')->getData();
foreach ($add_images as $add_image) {
$images[] = $add_image;
}
}
$data = [
...$form->getData(),
'images' => $images,
];
$data['contact_type'] = $type;
$event = new EventArgs(['form' => $form, 'data' => $data], $request);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_CONTACT_INDEX_COMPLETE);
$data = $event->getArgument('data');
// 件名を動的に設定
if ($type === self::ROUTE_OTHER) {
$subject = '[祈りの道具屋まなか] お問い合わせを受け付けました';
} elseif ($type === self::ROUTE_CATALOG) {
$subject = '[祈りの道具屋まなか] カタログの請求を受け付けました';
} elseif ($type === self::ROUTE_COORDINATE) {
$subject = '[祈りの道具屋まなか] コーディネートサービスのお申込みを受け付けました';
} elseif ($type === self::ROUTE_SHOWROOM && $data['which_showroom'] === self::SHOWROOM_RESERVED_GINZA) {
$subject = '[祈りの道具屋まなか] 銀座ショールームのご予約希望日を受け付けました';
} elseif ($type === self::ROUTE_SHOWROOM && $data['which_showroom'] === self::SHOWROOM_RESERVED_YOKOHAMA) {
$subject = '[祈りの道具屋まなか] 横浜ショールームのご予約希望日を受け付けました';
}
// メール送信
$this->mailService->sendContactMail($data, $subject);
return $this->redirectToRoute('contact_complete');
}
}
return [
'form' => $form->createView(),
'type' => $type,
];
}
/**
* お問い合わせ完了画面.
*
* @Route("/contact/complete", name="contact_complete", methods={"GET"})
* @Template("Contact/complete.twig")
*/
public function complete()
{
return [];
}
/**
* 各フォームに共通するフォームを追加.
*/
private function addCommonForms(FormBuilderInterface $builder)
{
// 画像関連
$builder
->add('coordinate_image', FileType::class, [
'multiple' => true,
'required' => false,
'mapped' => false,
])
->add('images', CollectionType::class, [
'entry_type' => HiddenType::class,
'required' => false,
'prototype' => true,
'mapped' => false,
'allow_add' => true,
'allow_delete' => true,
])
->add('add_images', CollectionType::class, [
'entry_type' => HiddenType::class,
'required' => false,
'prototype' => true,
'mapped' => false,
'allow_add' => true,
'allow_delete' => true,
])
->add('delete_images', CollectionType::class, [
'entry_type' => HiddenType::class,
'required' => false,
'prototype' => true,
'mapped' => false,
'allow_add' => true,
'allow_delete' => true,
]);
}
/**
* 画像アップロード時にリクエストされるメソッド.
*
* @see https://pqina.nl/filepond/docs/api/server/#process
* @Route("/coordinate/image/process", name="coordinate_image_process", methods={"POST"})
*/
public function imageProcess(Request $request)
{
if (!$request->isXmlHttpRequest() && $this->isTokenValid()) {
throw new BadRequestHttpException();
}
$form_id = $request->get('id');
$images = $request->files->get($form_id);
$allowExtensions = ['gif', 'jpg', 'jpeg', 'png'];
$files = [];
if (count($images) > 0) {
foreach ($images as $img) {
foreach ($img as $image) {
// ファイルフォーマット検証
$mimeType = $image->getMimeType();
if (0 !== strpos($mimeType, 'image')) {
throw new UnsupportedMediaTypeHttpException();
}
// 拡張子
$extension = $image->getClientOriginalExtension();
if (!in_array(strtolower($extension), $allowExtensions)) {
throw new UnsupportedMediaTypeHttpException();
}
$filename = date('mdHis') . uniqid('_') . '.' . $extension;
$image->move($this->eccubeConfig['eccube_temp_image_dir'], $filename);
$files[] = $filename;
}
}
}
return new Response(array_shift($files));
}
/**
* アップロード画像を取得する際にコールされるメソッド.
*
* @see https://pqina.nl/filepond/docs/api/server/#load
* @Route("/coordinate/image/load", name="coordinate_image_load", methods={"GET"})
*/
public function imageLoad(Request $request)
{
if (!$request->isXmlHttpRequest()) {
throw new BadRequestHttpException();
}
$dirs = [
$this->eccubeConfig['eccube_save_image_dir'],
$this->eccubeConfig['eccube_temp_image_dir'],
];
foreach ($dirs as $dir) {
if (strpos($request->query->get('source'), '..') !== false) {
throw new NotFoundHttpException();
}
$image = \realpath($dir . '/' . $request->query->get('source'));
$dir = \realpath($dir);
if (\is_file($image) && \str_starts_with($image, $dir)) {
$file = new \SplFileObject($image);
return $this->file($file, $file->getBasename());
}
}
throw new NotFoundHttpException();
}
/**
* アップロード画像をすぐ削除する際にコールされるメソッド.
*
* @see https://pqina.nl/filepond/docs/api/server/#revert
* @Route("/coordinate/image/revert", name="coordinate_image_revert", methods={"DELETE"})
*/
public function imageRevert(Request $request)
{
if (!$request->isXmlHttpRequest() && $this->isTokenValid()) {
throw new BadRequestHttpException();
}
$tempFile = $this->eccubeConfig['eccube_temp_image_dir'] . '/' . $request->getContent();
if (is_file($tempFile) && stripos(realpath($tempFile), $this->eccubeConfig['eccube_temp_image_dir']) === 0) {
$fs = new Filesystem();
$fs->remove($tempFile);
return new Response(null, Response::HTTP_NO_CONTENT);
}
throw new NotFoundHttpException();
}
}