<?php
namespace Customize\Controller;
use Customize\Repository\CouponRepository;
use Customize\Service\CouponCodeGenerator;
use Customize\Service\ReferralLinkGenerator;
use Eccube\Controller\EntryController;
use Plugin\ECCUBE4LineLoginIntegration42\Controller\LineLoginIntegrationController;
use Eccube\Entity\BaseInfo;
use Eccube\Entity\Master\CustomerStatus;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Eccube\Form\Type\Front\EntryType;
use Eccube\Repository\BaseInfoRepository;
use Eccube\Repository\CustomerRepository;
use Eccube\Repository\Master\CustomerStatusRepository;
use Eccube\Repository\PageRepository;
use Eccube\Service\CartService;
use Eccube\Service\MailService;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception as HttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Form\FormError;
class EntryControllerExtends extends EntryController
{
/**
* @var CustomerStatusRepository
*/
protected $customerStatusRepository;
/**
* @var ValidatorInterface
*/
protected $recursiveValidator;
/**
* @var MailService
*/
protected $mailService;
/**
* @var BaseInfo
*/
protected $BaseInfo;
/**
* @var CustomerRepository
*/
protected $customerRepository;
/**
* @var EncoderFactoryInterface
*/
protected $encoderFactory;
/**
* @var TokenStorageInterface
*/
protected $tokenStorage;
/**
* @var \Eccube\Service\CartService
*/
protected $cartService;
/**
* @var PageRepository
*/
protected $pageRepository;
/**
* @var CouponRepository
*/
protected $couponRepository;
/**
* @var CouponCodeGenerator
*/
private $couponCodeGenerator;
/**
* @var ReferralLinkGenerator
*/
private $referralCodeGenerator;
/**
* EntryController constructor.
*
* @param CartService $cartService
* @param CustomerStatusRepository $customerStatusRepository
* @param MailService $mailService
* @param BaseInfoRepository $baseInfoRepository
* @param CustomerRepository $customerRepository
* @param EncoderFactoryInterface $encoderFactory
* @param ValidatorInterface $validatorInterface
* @param TokenStorageInterface $tokenStorage
* @param PageRepository $pageRepository
* @param CouponRepository $couponRepository
* @param CouponCodeGenerator $couponCodeGenerator
* @param ReferralLinkGenerator $referralCodeGenerator
*/
public function __construct(
CartService $cartService,
CustomerStatusRepository $customerStatusRepository,
MailService $mailService,
BaseInfoRepository $baseInfoRepository,
CustomerRepository $customerRepository,
EncoderFactoryInterface $encoderFactory,
ValidatorInterface $validatorInterface,
TokenStorageInterface $tokenStorage,
PageRepository $pageRepository,
CouponRepository $couponRepository,
CouponCodeGenerator $couponCodeGenerator,
ReferralLinkGenerator $referralCodeGenerator
) {
$this->customerStatusRepository = $customerStatusRepository;
$this->mailService = $mailService;
$this->BaseInfo = $baseInfoRepository->get();
$this->customerRepository = $customerRepository;
$this->encoderFactory = $encoderFactory;
$this->recursiveValidator = $validatorInterface;
$this->tokenStorage = $tokenStorage;
$this->cartService = $cartService;
$this->pageRepository = $pageRepository;
$this->couponRepository = $couponRepository;
$this->couponCodeGenerator = $couponCodeGenerator;
$this->referralCodeGenerator = $referralCodeGenerator;
}
/**
* 会員登録前.
*
* @Route("/entry/before", name="entry_before", methods={"GET"})
* @Template("Entry/before.twig")
*/
public function before(Request $request)
{
$sendto = $request->query->get('sendto'); // detail / list / homepage
$param = $request->query->get('param'); // detail=商品ID / list=キーワード
$referrer_code = $request->query->get('rc'); // 紹介コード
// ログイン済みかどうかを判定する →ログイン済みの場合はリダイレクトする
$Customer = $this->getUser();
if($Customer){
// パラメータに合わせてリダイレクトする
// 商品詳細/商品一覧/TOPのいずれかが指定されていればリダイレクトする
if($sendto == 'detail'){
$url = $this->generateUrl('product_detail', ['id' => $param]);
return new RedirectResponse($url);
} else if($sendto == 'list'){
$url = $this->generateUrl('product_list', ['name' => $param], UrlGeneratorInterface::RELATIVE_PATH);
return new RedirectResponse($url);
} else if($sendto == 'homepage'){
$url = $this->generateUrl('homepage');
return new RedirectResponse($url);
}
}
// 会員登録後のリダイレクト先が設定されていればSessionに格納する
if($sendto != null){
$this->session->set('sendto', $sendto);
}
if($param != null){
$this->session->set('param', $param);
}
if($referrer_code != null){
$this->session->set('entry.referrer.code', $referrer_code);
// 不正な紹介リンクではないかチェック
try {
$referralCode = self::getReferrerCode($request);
if ($referralCode != null) {
$this->referralCodeGenerator->decode(
(string) $referralCode
);
}
} catch (\InvalidArgumentException $ex) {
$this->session->remove('entry.referrer.code');
return [
"invalidCode" => true
];
}
}
// LPから来たかどうかを判定しSessionに格納する
$fromZitanLp = $request->query->get('fromZitanLp');
if($fromZitanLp != null && $fromZitanLp == 1){
$this->session->set('fromZitanLp', $fromZitanLp);
}
$fromSpotMenuLp = $request->query->get('fromSpotMenuLp');
if($fromSpotMenuLp != null && $fromSpotMenuLp == 1){
$this->session->set('fromSpotMenuLp', $fromSpotMenuLp);
}
$fromOriginalMenuLp = $request->query->get('fromOriginalMenuLp');
if($fromOriginalMenuLp != null && $fromOriginalMenuLp == 1){
$this->session->set('fromOriginalMenuLp', $fromOriginalMenuLp);
}
$fromTrigalCp = $request->query->get('fromTrigalCp');
if($fromTrigalCp != null && $fromTrigalCp == 1){
$this->session->set('fromTrigalCp', $fromTrigalCp);
}
$fromNewOpenRestoLp = $request->query->get('fromNewOpenRestoLp');
if($fromNewOpenRestoLp != null && $fromNewOpenRestoLp == 1){
$this->session->set('fromNewOpenRestoLp', $fromNewOpenRestoLp);
}
return ["invalidCode" => false];
}
/**
* 会員登録画面.
*
* @Route("/entry", name="entry", methods={"GET", "POST"})
* @Route("/entry", name="entry_confirm", methods={"GET", "POST"})
* @Template("Entry/index.twig")
*/
public function index(Request $request)
{
// Line経由で遷移しているかどうかを判定する
$lineUserId = $this->session->get(LineLoginIntegrationController::PLUGIN_LINE_LOGIN_INTEGRATION_SSO_USERID);
$isFromLine = false;
$dummyPass = $this->eccubeConfig['eccube_default_password'];
if($lineUserId){
$isFromLine = true;
}
// LPから来たかどうかを判定しSessionにパラメータ設定する
$fromZitanLp = $request->query->get('fromZitanLp');
if($fromZitanLp != null && $fromZitanLp == 1){
$this->session->set('fromZitanLp', $fromZitanLp);
}
$fromSpotMenuLp = $request->query->get('fromSpotMenuLp');
if($fromSpotMenuLp != null && $fromSpotMenuLp == 1){
$this->session->set('fromSpotMenuLp', $fromSpotMenuLp);
}
$fromOriginalMenuLp = $request->query->get('fromOriginalMenuLp');
if($fromOriginalMenuLp != null && $fromOriginalMenuLp == 1){
$this->session->set('fromOriginalMenuLp', $fromOriginalMenuLp);
}
$fromTrigalCp = $request->query->get('fromTrigalCp');
if($fromTrigalCp != null && $fromTrigalCp == 1){
$this->session->set('fromTrigalCp', $fromTrigalCp);
}
$fromNewOpenRestoLp = $request->query->get('fromNewOpenRestoLp');
if($fromNewOpenRestoLp != null && $fromNewOpenRestoLp == 1){
$this->session->set('fromNewOpenRestoLp', $fromNewOpenRestoLp);
}
// /entry?c=xxxで来た紹介コードを初回GETでデコード→referrer_idをセッションentry.referralに保持。失敗時はセッションをクリアしつつエラーフラッシュ。
$referralCode = self::getReferrerCode($request);
if ($referralCode != null) {
$referrer_id = $this->referralCodeGenerator->decode(
(string) $referralCode
);
$this->session->set('entry.referral', $referrer_id);
}
if ($this->isGranted('ROLE_USER')) {
log_info('認証済のためログイン処理をスキップ');
return $this->redirectToRoute('mypage');
}
/** @var $Customer \Eccube\Entity\Customer */
$Customer = $this->customerRepository->newCustomer();
/* @var $builder \Symfony\Component\Form\FormBuilderInterface */
$builder = $this->formFactory->createBuilder(EntryType::class, $Customer);
$event = new EventArgs(
[
'builder' => $builder,
'Customer' => $Customer,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_ENTRY_INDEX_INITIALIZE);
/* @var $form \Symfony\Component\Form\FormInterface */
$form = $builder->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
switch ($request->get('mode')) {
case 'confirm':
log_info('会員登録確認開始');
log_info('会員登録確認完了');
return $this->render(
'Entry/confirm.twig',
[
'form' => $form->createView(),
'Page' => $this->pageRepository->getPageByRoute('entry_confirm'),
'isFromLine' => $isFromLine,
]
);
case 'complete':
log_info('会員登録開始');
$encoder = $this->encoderFactory->getEncoder($Customer);
$salt = $encoder->createSalt();
$password = $encoder->encodePassword($Customer->getPlainPassword(), $salt);
$secretKey = $this->customerRepository->getUniqueSecretKey();
// 紹介リンクからの登録である場合
// 紹介者のコードが上限を超えている場合にはエラーを返す
$referral = $this->session->get('entry.referral');
if ($referral) {
$Referrer = $this->customerRepository->find($referral['id'] ?? 0);
if (!$Referrer) {
$form->addError(new FormError('紹介コードが無効です。'));
} else {
$limit = (int) $this->eccubeConfig['max_issue_count_refer_friend'];
$issued = $this->couponRepository->getCountForIssuedReferralCoupon($Referrer);
if ($issued >= $limit) {
$form->addError(new FormError('紹介者が紹介できる友達の上限を超えました'));
} else {
$Customer->setReferrer($Referrer);
}
}
if ($form->getErrors(true)->count() > 0) {
// 必要なら紹介情報は破棄
$this->session->remove('entry.referral');
return $this->render('Entry/confirm.twig', [
'form' => $form->createView(),
'Page' => $this->pageRepository->getPageByRoute('entry_confirm'),
'isFromLine' => $isFromLine,
]);
}
}
$Customer
->setSalt($salt)
->setPassword($password)
->setSecretKey($secretKey)
->setPoint(0);
$this->entityManager->persist($Customer);
$this->entityManager->flush();
// 紹介コードで登録を行った場合
if ($Customer->getReferrer()) {
$couponCode = $this->couponCodeGenerator->generateReferralFriendCode(false);
//
$coupon = $this->couponRepository->issueReferralCoupons($Customer->getReferrer(), $Customer, $couponCode, false);
if($coupon != null && $Customer != null) {
$this->couponRepository->attachCouponToCustomer($coupon, $Customer);
}
}
log_info('会員登録完了');
$event = new EventArgs(
[
'form' => $form,
'Customer' => $Customer,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_ENTRY_INDEX_COMPLETE);
$activateFlg = $this->BaseInfo->isOptionCustomerActivate();
// 仮会員設定が有効な場合は、確認メールを送信し完了画面表示.
if ($activateFlg) {
$activateUrl = $this->generateUrl('entry_activate', ['secret_key' => $Customer->getSecretKey()], UrlGeneratorInterface::ABSOLUTE_URL);
// メール送信
$this->mailService->sendCustomerConfirmMail($Customer, $activateUrl);
if ($event->hasResponse()) {
return $event->getResponse();
}
log_info('仮会員登録完了画面へリダイレクト');
return $this->redirectToRoute('entry_complete');
} else {
// 仮会員設定が無効な場合は、会員登録を完了させる.
$qtyInCart = $this->entryActivate($request, $Customer->getSecretKey());
// カートに商品が入っていれば購入確認画面に遷移する
if (0 < $qtyInCart) {
return $this->redirectToRoute('shopping', [
'secret_key' => $Customer->getSecretKey(),
'qtyInCart' => $qtyInCart,
]);
}
// URLを変更するため完了画面にリダイレクト
return $this->redirectToRoute('entry_activate', [
'secret_key' => $Customer->getSecretKey(),
'qtyInCart' => $qtyInCart,
]);
}
}
}
return [
'form' => $form->createView(),
'isFromLine' => $isFromLine,
'dummyPass' => $dummyPass,
];
}
/**
* 会員登録完了画面.
*
* @Route("/entry/complete", name="entry_complete", methods={"GET"})
* @Template("Entry/complete.twig")
*/
public function complete()
{
return [];
}
/**
* 会員のアクティベート(本会員化)を行う.
*
* @Route("/entry/activate/{secret_key}/{qtyInCart}", name="entry_activate", methods={"GET"})
* @Template("Entry/activate.twig")
*/
public function activate(Request $request, $secret_key, $qtyInCart = null)
{
$errors = $this->recursiveValidator->validate(
$secret_key,
[
new Assert\NotBlank(),
new Assert\Regex(
[
'pattern' => '/^[a-zA-Z0-9]+$/',
]
),
]
);
if (!$this->session->has('eccube.login.target.path')) {
$this->setLoginTargetPath($this->generateUrl('mypage', [], UrlGeneratorInterface::ABSOLUTE_URL));
}
if (!is_null($qtyInCart)) {
// Line連携ログイン稼動か
$Customer = $this->getUser();
$lineLoginIntegration = $Customer->getLineLoginIntegration();
$isLineRelatedUser = false;
if($lineLoginIntegration != null){
$isLineRelatedUser = true;
}
// 紹介リンクからの登録か
$isReferralUser = false;
if ($Customer->getReferrer() != null) {
$isReferralUser = true;
}
// 遷移先ページが指定されていれば先にリダイレクト処理する
$sendto = $this->session->get('sendto');
$param = $this->session->get('param');
// 商品詳細/商品一覧/TOPのいずれかが指定されていればリダイレクトする
if($sendto == 'detail'){
$url = $this->generateUrl('product_detail', ['id' => $param]);
return new RedirectResponse($url);
} else if($sendto == 'list'){
$url = $this->generateUrl('product_list', ['name' => $param], UrlGeneratorInterface::RELATIVE_PATH);
return new RedirectResponse($url);
} else if($sendto == 'homepage'){
$url = $this->generateUrl('homepage');
return new RedirectResponse($url);
}
// どのLPからの遷移か特定するパラメータ
$fromZitanLp = $this->session->get('fromZitanLp');
$fromSpotMenuLp = $this->session->get('fromSpotMenuLp');
$fromOriginalMenuLp = $this->session->get('fromOriginalMenuLp');
$fromTrigalCp = $this->session->get('fromTrigalCp');
$fromNewOpenRestoLp = $this->session->get('fromNewOpenRestoLp');
return [
'qtyInCart' => $qtyInCart,
'isLineRelatedUser' => $isLineRelatedUser,
'isReferralUser' => $isReferralUser,
'fromZitanLp' => $fromZitanLp,
'fromSpotMenuLp' => $fromSpotMenuLp,
'fromOriginalMenuLp' => $fromOriginalMenuLp,
'fromTrigalCp' => $fromTrigalCp,
'fromNewOpenRestoLp' => $fromNewOpenRestoLp,
];
} elseif ($request->getMethod() === 'GET' && count($errors) === 0) {
// 会員登録処理を行う
$qtyInCart = $this->entryActivate($request, $secret_key);
return [
'qtyInCart' => $qtyInCart,
];
}
throw new HttpException\NotFoundHttpException();
}
/**
* 会員登録処理を行う
*
* @param Request $request
* @param $secret_key
*
* @return \Eccube\Entity\Cart|mixed
*/
private function entryActivate(Request $request, $secret_key)
{
log_info('本会員登録開始');
$Customer = $this->customerRepository->getProvisionalCustomerBySecretKey($secret_key);
if (is_null($Customer)) {
throw new HttpException\NotFoundHttpException();
}
$CustomerStatus = $this->customerStatusRepository->find(CustomerStatus::REGULAR);
$Customer->setStatus($CustomerStatus);
$this->entityManager->persist($Customer);
$this->entityManager->flush();
log_info('本会員登録完了');
$event = new EventArgs(
[
'Customer' => $Customer,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_ENTRY_ACTIVATE_COMPLETE);
// メール送信
$this->mailService->sendCustomerCompleteMail($Customer);
// 本会員登録してログイン状態にする
$token = new UsernamePasswordToken($Customer, null, 'customer', array('ROLE_USER'));
$this->tokenStorage->setToken($token);
log_info('ログイン済に変更。dtb_customer.id:'.$this->getUser()->getId());
// カートのマージなどの処理
$loginEvent = new InteractiveLoginEvent($request, $token);
$this->eventDispatcher->dispatch(
$loginEvent,
SecurityEvents::INTERACTIVE_LOGIN
);
// Assign session carts into customer carts
$Carts = $this->cartService->getCarts();
$qtyInCart = 0;
foreach ($Carts as $Cart) {
$qtyInCart += $Cart->getTotalQuantity();
}
if ($qtyInCart) {
$this->cartService->save();
}
return $qtyInCart;
}
/**
* 紹介コードを
* @param mixed $request
*/
private function getReferrerCode($request) {
if($request->query->get('rc') == null){
return $this->session->get('entry.referrer.code');
} else {
return $request->query->get('rc');
}
}
}