<?php 
/** 
 * Copyright(c) 2022 SYSTEM_KD 
 * Date: 2022/09/03 
 */ 
 
namespace Plugin\OrderStatusEx\EventSubscriber; 
 
 
use Doctrine\ORM\EntityManagerInterface; 
use Eccube\Entity\Master\OrderStatus; 
use Eccube\Entity\Order; 
use Eccube\Entity\Shipping; 
use Eccube\Event\TemplateEvent; 
use Eccube\Form\Type\Admin\OrderStatusSettingType; 
use Eccube\Repository\Master\OrderStatusRepository; 
use Eccube\Service\OrderStateMachineContext; 
use Eccube\Service\SystemService; 
use Eccube\Util\CacheUtil; 
use Plugin\OrderStatusEx\Controller\Admin\Seggin\Shop\OrderStatusExController; 
use Plugin\OrderStatusEx\Entity\OrderOrderStatus; 
use Plugin\OrderStatusEx\Entity\OrderStatusEvent; 
use Plugin\OrderStatusEx\Entity\OrderStatusEx; 
use Plugin\OrderStatusEx\Service\OrderStatusExConfigService; 
use Plugin\OrderStatusEx\Service\OrderStatusExService; 
use Plugin\OrderStatusEx\Service\TwigRenderService\EventSubscriber\TwigRenderTrait; 
use Symfony\Component\EventDispatcher\EventSubscriberInterface; 
use Symfony\Component\Form\FormFactoryInterface; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\RequestStack; 
use Symfony\Component\HttpFoundation\Session\SessionInterface; 
use Symfony\Component\HttpKernel\Event\ControllerEvent; 
use Symfony\Component\HttpKernel\KernelEvents; 
use Symfony\Component\Routing\RouterInterface; 
use Symfony\Component\Workflow\Event\Event; 
use Symfony\Component\Workflow\Event\TransitionEvent; 
 
class OrderStatusEventSubscriber implements EventSubscriberInterface 
{ 
 
    use TwigRenderTrait; 
 
    /** @var RouterInterface */ 
    protected $router; 
 
    /** @var FormFactoryInterface */ 
    protected $formFactory; 
 
    /** @var EntityManagerInterface */ 
    protected $entityManager; 
 
    /** @var OrderStatusExService */ 
    protected $orderStatusExService; 
 
    /** @var OrderStatusExController */ 
    protected $orderStatusExController; 
 
    /** @var CacheUtil */ 
    protected $cachUtil; 
 
    /** @var SessionInterface */ 
    protected $session; 
 
    /** @var SystemService */ 
    protected $systemService; 
 
    /** @var OrderStatusExConfigService */ 
    protected $orderStatusExConfigService; 
 
    /** @var RequestStack */ 
    private RequestStack $requestStack; 
 
    public function __construct( 
        RouterInterface            $router, 
        FormFactoryInterface       $formFactory, 
        EntityManagerInterface     $entityManager, 
        OrderStatusExService       $orderStatusExService, 
        OrderStatusExController    $orderStatusExController, 
        CacheUtil                  $cacheUtil, 
        SystemService              $systemService, 
        OrderStatusExConfigService $orderStatusExConfigService, 
        RequestStack               $requestStack 
    ) 
    { 
        $this->router = $router; 
        $this->formFactory = $formFactory; 
        $this->entityManager = $entityManager; 
        $this->orderStatusExService = $orderStatusExService; 
        $this->orderStatusExController = $orderStatusExController; 
        $this->cachUtil = $cacheUtil; 
        $this->systemService = $systemService; 
        $this->orderStatusExConfigService = $orderStatusExConfigService; 
        $this->requestStack = $requestStack; 
 
    } 
 
    /** 
     * 受注対応状況設定テンプレート 
     * 
     * @param TemplateEvent $event 
     * @return void 
     */ 
    public function onSettingShopOrderStatusTwig(TemplateEvent $event) 
    { 
 
        // リダイレクトしない場合はキャッシュクリア用フラグOFF 
        $session = $this->requestStack->getSession(); 
        $session->set(OrderStatusExService::CACHE_CLEAR_KEY, false); 
 
        /** @var Request $request */ 
        $request = $this->requestStack->getMainRequest(); 
 
        // 新規登録エラー用 
        $builder = $this->formFactory->createBuilder(OrderStatusSettingType::class, null); 
 
        $form = $builder->getForm(); 
        $form->get('color')->setData('#a3a3a3'); 
 
        if ('POST' === $request->getMethod()) { 
            $form->handleRequest($request); 
 
            if ($form->isSubmitted()) { 
                $form->isValid(); 
            } 
        } 
        $event->setParameter('createForm', $form->createView()); 
 
        $this->initRenderService($event); 
 
        // 新規登録ブロック追加 
        $this->createInsertBuilder() 
            ->find(".c-contentsArea__primaryCol") 
            ->setTargetId('order_status_ex_block') 
            ->setInsertModePrepend(); 
 
        // テーブル追加 
        $this->createInsertBuilder() 
            ->find('table > thead > tr') 
            ->setTargetId('order_status_ex_table_head') 
            ->setInsertModeAppend(); 
 
        // 削除ボタン 
        $child = $this->twigRenderService 
            ->eachChildBuilder() 
            ->findThis() 
            ->targetFindAndIndexKey("#orderStatusExIndex_", "orderStatusExIndex") 
            ->setInsertModeAppend(); 
 
        $this->twigRenderService 
            ->eachBuilder() 
            ->find("table > tbody > tr") 
            ->setEachIndexKey("orderStatusExIndex") 
            ->each($child->build()); 
 
        // 削除用モーダル 
        $this->createInsertBuilder() 
            ->find("#form") 
            ->setTargetId("OrderStatusDeleteModal") 
            ->setInsertModeAfter(); 
 
        $child = $this->twigRenderService 
            ->eachChildBuilder() 
            ->findThis() 
            ->find('td') 
            ->eq(2) 
            ->targetFindAndIndexKey("#orderStatusExIndex2_", "orderStatusExIndex2") 
            ->setInsertModeAppend(); 
 
        $this->twigRenderService 
            ->eachBuilder() 
            ->find("table > tbody > tr") 
            ->setEachIndexKey("orderStatusExIndex2") 
            ->each($child->build()); 
 
        $this->addTwigRenderSnippet( 
            '@OrderStatusEx/admin/Setting/Shop/order_status_add.twig', 
            '@OrderStatusEx/admin/Setting/Shop/order_status_add_js.twig' 
        ); 
    } 
 
    public function onKernelController(ControllerEvent $event) 
    { 
        $request = $event->getRequest(); 
        $route = $request->attributes->get('_route'); 
 
        if ('admin_setting_shop_order_status' === $route) { 
 
            $session = $this->requestStack->getSession(); 
 
            if ($session->get(OrderStatusExService::CACHE_CLEAR_KEY, false)) { 
                $this->systemService->switchMaintenance(true); 
 
                // Cache Clear 
                $session->set(OrderStatusExService::CACHE_CLEAR_KEY, false); 
                $this->cachUtil->clearCache(); 
 
                $this->systemService->disableMaintenance(); 
            } 
 
            // 新規登録Form 
            $builder = $this->formFactory->createBuilder(OrderStatusSettingType::class, null); 
 
            $form = $builder->getForm(); 
            $form->handleRequest($request); 
 
            // 新規登録分の登録処理 
            if ($form->isSubmitted()) { 
                if ($form->isValid()) { 
                    // 登録処理実施 
                    /** @var OrderStatus $orderStatus */ 
                    $orderStatus = $form->getData(); 
 
                    // 受注状態追加 
                    $masterResult = $this->orderStatusExService->getMasterNextId(OrderStatus::class); 
                    $orderStatus 
                        ->setId($masterResult->nextId) 
                        ->setSortNo($masterResult->nextSortNo); 
 
                    $this->entityManager->persist($orderStatus); 
                    $this->entityManager->flush(); 
 
                    // 色登録 
                    $color = $form->get('color')->getData(); 
                    $this->orderStatusExService->registerOrderStatusColor($orderStatus, $color); 
 
                    // マイページ用名称登録 
                    $customerOrderStatusName = $form->get('customer_order_status_name')->getData(); 
                    $this->orderStatusExService->registerCustomerOrderStatus($orderStatus, $customerOrderStatusName); 
 
                    // 移動先・イベント種別情報登録 
                    // 移動先取得 
                    $orderStatuses = $form->get('OrderStatuses')->getData(); 
 
                    // 選択イベント取得 
                    $activeEvent = $form->get('ActiveEvent')->getData(); 
 
                    // 他の受注状況拡張情報取得 
                    $orderStatusExs = $this->entityManager->getRepository(OrderStatusEx::class)->findAll(); 
                    $orderStatusEventRepository = $this->entityManager->getRepository(OrderStatusEvent::class); 
                    $selectEvents = []; 
                    /** @var OrderStatusEx $orderStatusEx */ 
                    foreach ($orderStatusExs as $orderStatusEx) { 
                        /** @var OrderStatusEvent $selectEventGroup */ 
                        $selectEventGroup = $orderStatusEventRepository->find($orderStatusEx->getMoveOrderStatusId()); 
                        if ($selectEventGroup) { 
                            $selectEvents[$orderStatusEx->getMoveOrderStatusId()] = $selectEventGroup->getSelectEventGroup(); 
                        } else { 
                            $selectEvents[$orderStatusEx->getMoveOrderStatusId()] = OrderStatusEvent::EVENT_GROUP_NONE; 
                        } 
                    } 
                    // 新規追加分のイベント設定 
                    $selectEvents[$orderStatus->getId()] = $activeEvent; 
 
                    $this->orderStatusExService->updateOrderStatusEx($orderStatus, $orderStatuses, $selectEvents); 
 
                    $this->entityManager->flush(); 
 
                    // リダイレクト 
                    $event->setController([$this->orderStatusExController, 'success']); 
                } 
 
            } else if ($request->getMethod() == 'POST') { 
                // Cache Clear ON 
                $session->set(OrderStatusExService::CACHE_CLEAR_KEY, true); 
            } 
        } 
    } 
 
    /** 
     * 受注状況の発送済み相当変更時 
     * 
     * @param TransitionEvent $event 
     * @return void 
     */ 
    public function onShip(TransitionEvent $event) 
    { 
 
        $tos = $event->getTransition()->getTos(); 
 
        if (in_array(OrderStatus::DELIVERED, $tos)) { 
            return; 
        } 
 
        /** @var Order $order */ 
        $order = $event->getSubject()->getOrder(); 
        $order->getShippings()->map(function (Shipping $shipping) { 
            if (!$shipping->isShipped()) { 
                $shipping->setShippingDate(new \DateTime()); 
            } 
        }); 
    } 
 
    public function onCompleted(Event $event) 
    { 
        /** @var $context OrderStateMachineContext */ 
        $context = $event->getSubject(); 
        $order = $context->getOrder(); 
 
        /** @var OrderStatus $newOrderStatus */ 
        $newOrderStatusId = $context->getStatus(); 
        /** @var OrderStatusRepository $orderStatusRepository */ 
        $orderStatusRepository = $this->entityManager->getRepository(OrderStatus::class); 
        $newOrderStatus = $orderStatusRepository->find($newOrderStatusId); 
 
        // 拡張情報へ選択したステータスを保持し表示ステータスに標準をセットする 
        $orderOrderStatus = $order->getOrderOrderStatus(); 
        if (!$orderOrderStatus) { 
            $orderOrderStatus = new OrderOrderStatus(); 
            $orderOrderStatus->setOrder($order); 
        } 
        $orderOrderStatus->setOrderStatus($newOrderStatus); 
        $this->entityManager->persist($orderOrderStatus); 
 
        // 集約保持モード 
        if (!$this->orderStatusExConfigService->isStrictMode()) { 
            $convertOrderStatus = $this->orderStatusExService->getConvertStatusByEvent($newOrderStatus); 
            $order->setOrderStatus($convertOrderStatus); 
        } 
    } 
 
    public static function getSubscribedEvents() 
    { 
        return [ 
            KernelEvents::CONTROLLER => 'onKernelController', 
            '@admin/Setting/Shop/order_status.twig' => 'onSettingShopOrderStatusTwig', 
            'workflow.order.transition.ship' => 'onShip', 
            'workflow.order.completed' => ['onCompleted', -300], 
        ]; 
    } 
}