【ECCUBE4】お問い合わせフォームに添付ファイルを追加する

まぐろ

ECCUBE4にて、お問い合わせフォームに添付ファイルを追加した
合わせてメール送信もファイルを添付するように改修を行う

ECCUBEでのフォームカスタマイズ方法

ECCUBEでは、FormTypeのカスタマイズをすると
フォームに項目が追加できる仕組みになっている

FormTypeカスタマイズではFormExtensionクラスを使用するので下記で実装してく

FormExtensionクラスを作成する

  • app/Customize/Form/Extension/ContactTypeExtension.phpを新規作成
<?php
namespace Customize\Form\Extension;

use Eccube\Form\Type\Front\ContactType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Customize\Service\FileUploader;

class ContactTypeExtension extends AbstractTypeExtension
{
    /**
     * @var FileUploader
     */
    private $fileUploader;

    /**
     * @var UrlGeneratorInterface
     */
    private $urlGenerator;

    public function __construct(FileUploader $fileUploader, UrlGeneratorInterface $urlGenerator) {
        $this->fileUploader = $fileUploader;
        $this->urlGenerator = $urlGenerator;
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // ここでformビルダーに添付ファイル項目を追加 (input[type=file])
        $builder->add('attachment', FileType::class, [
            'label' => '添付ファイル',
            'required' => false,
        ])
        // ファイルの場所を保持するhidden項目も追加
        ->add('filename', HiddenType::class);

        /**
         * SUBMIT前にファイルをアップロードしてfilenameにセットする
         */
        $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event){
            $data = $event->getData();
            // ファイルが選択されている場合
            if (!empty($data['attachment'])) {
                // ファイルをアップロード
                $filename = $this->fileUploader->upload($data['attachment']);
                $data['filename'] = $this->urlGenerator->generate('homepage', [], true) . $filename;
                unset($data['attachment']);
                // アップロードしたデータを保存
                $event->setData($data);
            }
        });
    }

    /**
     * {@inheritdoc}
     */
    public static function getExtendedTypes(): iterable
    {
        yield ContactType::class;
    }
}

EC-CUBE 4.0では、getExtendedType関数が必須、
EC-CUBE 4.1以降は、getExtendedType関数が必須なので注意

public function getExtendedType()
{
    return ContactType::class;
}

public static function getExtendedTypes(): iterable
{
    yield ContactType::class;
}

FileUploaderクラスを作成する

  • 順番が前後したけど、上記で作成したContactTypeExtensionで使用しているCustomize\Service\FileUploader を新規作成
<?php

namespace Customize\Service;

use Eccube\Common\EccubeConfig;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class FileUploader
{
    /**
     * @var EccubeConfig
     */
    private $eccubeConfig;

    public function __construct(EccubeConfig $eccubeConfig) {
        $this->eccubeConfig = $eccubeConfig;
    }

    /**
     * ファイルをアップロードする
    **/
    public function upload(UploadedFile $file)
    {
        $filename = date('mdHis') . uniqid('_') . '.' . $file->guessExtension();

        $file->move(
            $this->eccubeConfig["eccube_save_image_dir"]. '/contact',
            $filename
        );

        return "contact/$filename";
    }
}

MailServiceクラスを作成する

今回、メール送信時にファイル添付を行うため、既存の送信処理を改修する必要がある
そのため既存のMailService::sendContactMailを下記手順でオーバーロードする

  • app/Customize/Service/MailService.php を新規作成
<?php

namespace Customize\Service;

use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;

class MailService extends \Eccube\Service\MailService
{
    /**
     * Send contact mail.
     *
     * @param $formData お問い合わせ内容
     */
    public function sendContactMail($formData)
    {
        log_info('お問い合わせ受付メール送信開始');

        $MailTemplate = $this->mailTemplateRepository->find($this->eccubeConfig['eccube_contact_mail_template_id']);

        $body = $this->twig->render($MailTemplate->getFileName(), [
            'data' => $formData,
            'BaseInfo' => $this->BaseInfo,
        ]);

        // 問い合わせ者にメール送信
        $message = (new Email())
            ->subject('['.$this->BaseInfo->getShopName().'] '.$MailTemplate->getMailSubject())
            ->from(new Address($this->BaseInfo->getEmail02(), $this->BaseInfo->getShopName()))
            ->to($this->convertRFCViolatingEmail($formData['email']))
            ->bcc($this->BaseInfo->getEmail02())
            ->replyTo($this->BaseInfo->getEmail02())
            ->returnPath($this->BaseInfo->getEmail04());

        // ⭐️追加:ファイル添付
        if (!empty($formData['filename'])) {
            $message->attachFromPath($this->eccubeConfig["eccube_save_image_dir"]. '/'. $formData['filename']);
        }

        // HTMLテンプレートが存在する場合
        $htmlFileName = $this->getHtmlTemplate($MailTemplate->getFileName());
        if (!is_null($htmlFileName)) {
            $htmlBody = $this->twig->render($htmlFileName, [
                'data' => $formData,
                'BaseInfo' => $this->BaseInfo,
            ]);

            $message
                ->text($body)
                ->html($htmlBody);
        } else {
            $message->text($body);
        }

        $event = new EventArgs(
            [
                'message' => $message,
                'formData' => $formData,
                'BaseInfo' => $this->BaseInfo,
            ],
            null
        );
        $this->eventDispatcher->dispatch($event, EccubeEvents::MAIL_CONTACT);

        try {
            $this->mailer->send($message);
            log_info('お問い合わせ受付メール送信完了');
        } catch (TransportExceptionInterface $e) {
            log_critical($e->getMessage());
        }

    }
}

既存のsrc/Eccube/Service/MailService::sendContactMailをコピーして、
そこにファイル添付処理を追加してるだけ

あとはnamespaceとかextendsの部分を変更してる

  • app/Customize/Resource/config/services.yaml を新規作成
services:
  Customize\Service\MailService:
    public: false
    autowire: true
    decorates: Eccube\Service\MailService

これにより既存のMailServiceよりも今回作成したMailServiceが優先されるようになる

添付ファイル項目を表示するためtwigを編集

  • app/template/{テーマ}/Contact/index.twig を編集
    ない場合はsrc/Eccube/Resource/template/{テーマ}/Contact/index.twigをコピーして新規作成する

長くなるので追加箇所だけ記載する

<!-- ⭐️ 既存のformタグにenctype="multipart/form-data" を追加 -->
<form method="post" action="{{ url('contact') }}" class="h-adr" enctype="multipart/form-data" novalidate>

  <!-- ⭐️ 添付ファイル項目を追加 -->
   <dl>
     <dt>
       {{ form_label(form.attachment, '添付ファイル', { 'label_attr': { 'class': 'ec-label' }}) }}
     </dt>
     <dd>
       <div class="ec-input{{ has_errors(form.attachment) ? ' error' }}">
         {{ form_widget(form.attachment) }}
         {{ form_errors(form.attachment) }}
         {{ form_widget(form.filename) }}
       </div>
       {% if form.filename.vars.data != '' %}
         <img src="{{ asset(form.filename.vars.data, 'save_image') }}" style="width: 150px !important;" />
       {% endif %}
     </dd>
   </dl>

  • app/template/{テーマ}/Contact/config.twig を編集
    ない場合はsrc/Eccube/Resource/template/{テーマ}/Contact/config.twigをコピーして新規作成する

長くなるので追加箇所だけ記載する

<!-- ⭐️ 添付ファイル項目を追加 -->  
{% if form.filename.vars.data != '' %}
    <dl>
      <dt>
        {{ form_label(form.filename, '添付ファイル', { 'label_attr': { 'class': 'ec-label' }}) }}
      </dt>
      <dd>
        <img src="{{ asset(form.filename.vars.data, 'save_image') }}" style="width: 150px !important;" />
        {{ form_widget(form.filename, { type : 'hidden' }) }}
      </dd>
     </dl>
{% endif %}

これで最後にキャッシュ管理からキャッシュ削除すれば完成

補足

  • ContactTypeExtensionの下記箇所で
    ファイルのアップロード & ファイル名の設定をしている
       /**
         * SUBMIT前にファイルをアップロードしてfilenameにセットする
         */
        $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event){
            $data = $event->getData();
            if (!empty($data['attachment'])) {
                $filename = $this->fileUploader->upload($data['attachment']);
                $data['filename'] = $this->urlGenerator->generate('homepage', [], true) . $filename;
                unset($data['attachment']);
                $event->setData($data);
            }
        });

問い合わせはテーブルがない (=Entityを使用しない)ので、
ゲッター・セッターは使用せずに、PRE_SUBMITイベントで
新しいデータを $event->setData($data); でセットする

\ 案件のご依頼・ご相談はこちらから /