<?php
/**
* Created by PhpStorm.
* User: hls
* Date: 2019-08-02
* Time: 15:31
*/
namespace Plugin\ProductOption4;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManager;
use Eccube\Application;
use Eccube\Entity\Delivery;
use Eccube\Entity\Order;
use Eccube\Entity\OrderItem;
use Eccube\Entity\Product;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Eccube\Event\TemplateEvent;
use Eccube\Form\Type\Admin\OrderType;
use Eccube\Form\Type\Admin\SearchProductType;
use Eccube\Repository\BaseInfoRepository;
use Eccube\Repository\Master\ProductStatusRepository;
use Eccube\Service\CartService;
use Eccube\Service\OrderHelper;
use Eccube\Service\PurchaseFlow\PurchaseFlow;
use Plugin\ProductOption4\Entity\ProductOptionCategory;
use Plugin\ProductOption4\Entity\ProductOptionName;
use Plugin\ProductOption4\Entity\ProductOptionOrderItemGroup;
use Plugin\ProductOption4\Entity\ProductOptionShoppingCartItemGroup;
use Plugin\ProductOption4\Events\CartEvent;
use Plugin\ProductOption4\Events\ShoppingEvent;
use Plugin\ProductOption4\Repository\ProductOptionCategoryRepository;
use Plugin\ProductOption4\Repository\ProductOptionNameRepository;
use Psr\Container\ContainerInterface;
use Symfony\Bundle\TwigBundle\TwigEngine;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormFactory;
use Symfony\Component\Form\FormFactoryBuilderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Serializer\SerializerInterface;
use Plugin\ProductOption4\Service\MailService;
class ProductOptionEvent implements EventSubscriberInterface
{
/**
* @var ProductOptionNameRepository
*/
protected $productOptionNameRepository;
/**
* @var CartService
*/
protected $cartService;
private $app;
private $container;
protected $baseInfo;
protected $cartFlow;
protected $orderHelper;
/**
* @var EntityManager
*/
protected $entityManager;
/**
* @var ProductOptionCategoryRepository
*/
protected $productOptionCategoryRepository;
/**
* @var TwigEngine
*/
protected $twigEngine;
/**
* @var Request
*/
protected $request;
/**
* @var FormFactory
*/
protected $formFactory;
/**
* @var SerializerInterface
*/
protected $serializer;
/**
* @var MailService
*/
protected $mailService;
public function __construct(ProductOptionCategoryRepository $productOptionCategoryRepository,
ProductOptionNameRepository $productOptionNameRepository,
Application $app,
ContainerInterface $container,
CartService $cartService,
BaseInfoRepository $baseInfoRepository,
PurchaseFlow $cartFlow,
OrderHelper $orderHelper,
FormFactory $formFactory,
SerializerInterface $serializer,
MailService $mailService
)
{
$this->productOptionCategoryRepository = $productOptionCategoryRepository;
$this->productOptionNameRepository = $productOptionNameRepository;
$this->app = $app;
$this->container = $container;
$this->cartService = $cartService;
$this->baseInfo = $baseInfoRepository->get();
$this->cartFlow = $cartFlow;
$this->orderHelper = $orderHelper;
$this->entityManager = $this->container->get('doctrine.orm.entity_manager');
$this->twigEngine = $this->container->get('templating');
$this->request = $this->container->get('request_stack')->getMasterRequest();
$this->formFactory = $formFactory;
$this->serializer = $serializer;
$this->mailService = $mailService;
}
/**
* @return array
*/
public static function getSubscribedEvents()
{
return [
'Product/detail.twig' => 'productDetailEvent',
// // shopping cart page override
'Cart/index.twig' => 'twigFrontendCartIndexEvent',
// 'Shopping/index.twig' => 'twigFrontendShoppingIndexEvent',
'Block/cart.twig' => 'twigFrontendBlockCartEvent',
// 'Shopping/confirm.twig' => 'twigFrontendShoppingConfirm',
// My page order history
'Mypage/history.twig' => 'twigMypageHistory',
'@admin/Product/index.twig' => 'adminProductIndexTemplateEvent',
// override the admin product edit page, add the extra product edit option html
'@admin/Product/product.twig' => 'adminProductTemplateEvent',
'@admin/Product/csv_product.twig' => 'adminCsvProductTemplateEvent',
// backend order edit page override
'@admin/Order/edit.twig' => 'adminOrderEditTemplateEvent',
// override order export event
'@admin/Order/index.twig' => 'adminOrderIndexTemplateEvent',
// override export pdf
'@admin/Order/order_pdf.twig' => 'adminOrderPdfTemplateEvent',
EccubeEvents::ADMIN_PRODUCT_EDIT_COMPLETE => 'adminEditComplete',
EccubeEvents::FRONT_PRODUCT_CART_ADD_INITIALIZE => 'frontendCartAddInit',
// 添加产品后处理产品option
EccubeEvents::FRONT_PRODUCT_CART_ADD_COMPLETE => 'frontendCartAddComplete',
EccubeEvents::FRONT_SHOPPING_COMPLETE_INITIALIZE => 'frontendShoppingComplete',
];
}
public function frontendCartAddInit(EventArgs $event)
{
$builder = $event->getArgument('builder');
//$event->setArgument('builder', null);
}
/**
* Add product to cart, update the product option data
* @param EventArgs $event
*/
public function frontendCartAddComplete(EventArgs $event)
{
$eventClass = new CartEvent($this->cartService, $this->container, $this->baseInfo);
$eventClass->frontendCartAddCompleteEvent($event);
}
/**
* User order history update the order total price
*
* @param EventArgs $event
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
*/
public function frontendShoppingComplete(EventArgs $event)
{
$order = $event->getArgument('Order');
$totalPlus = $this->entityManager->getRepository(ProductOptionOrderItemGroup::class)->calculateProductOptionTotalPlus($order);
$order->setSubTotal($order->getSubTotal() + $totalPlus);
$order->setTotal($order->getTotal() + $totalPlus);
$order->setPaymentTotal($order->getPaymentTotal() + $totalPlus);
$this->entityManager->persist($order);
$this->entityManager->flush();
$productOptionOrderItemGroups = $this->entityManager->getRepository(ProductOptionOrderItemGroup::class)
->findBy(array(
'order' => $order,
));
// $this->mailService->sendOrderMail($order, $productOptionOrderItemGroups);
$this->entityManager->flush();
// remove all the product option data
// get product option cart groups
$cartOptionGroups = $this->entityManager->getRepository(ProductOptionShoppingCartItemGroup::class)->findAll();
foreach ($cartOptionGroups as $og) {
foreach ($og->getProductOptionShoppingCartItems() as $it) {
$this->entityManager->remove($it);
}
$this->entityManager->remove($og);
}
$this->entityManager->flush();
}
public function twigFrontendShoppingIndexEvent(TemplateEvent $event)
{
$eventClass = new ShoppingEvent($this->cartService, $this->container, $this->baseInfo);
$eventClass->twigFrontendShoppingIndexEvent($event, $this->cartFlow, $this->orderHelper);
}
public function twigFrontendBlockCartEvent(TemplateEvent $event) {
$event->setSource('abc');
}
public function twigFrontendShoppingConfirm(TemplateEvent $event)
{
$eventClass = new ShoppingEvent($this->cartService, $this->container, $this->baseInfo);
$eventClass->twigFrontendShoppingConfirm($event, $this->cartFlow, $this->orderHelper);
}
public function twigFrontendCartIndexEvent(TemplateEvent $event)
{
$eventClass = new CartEvent($this->cartService, $this->container, $this->baseInfo);
$eventClass->twigFrontendCartIndexEvent($event);
}
/**
* @param TemplateEvent $event
*/
public function productDetailEvent(TemplateEvent $event)
{
$source = $event->getSource();
#-- regex-replace an occurence by count
$productId = $this->container->get('request_stack')->getMasterRequest()->get('id');
$template = $this->container->get('templating');
$entityManager = $this->container->get('doctrine.orm.entity_manager');
$product = $entityManager->getRepository(Product::class)->find($productId);
$options = $entityManager->getRepository(ProductOptionName::class)->getData($product);
if (count($options) === 1 && count($options[0]['options']) === 0) {
} else {
$options = $template->render('ProductOption4/Resource/template/default/product_options.twig', [
'options' => $options,
]);
$sourceUpdated = str_replace('<div class="ec-numberInput">', $options . '<div class="ec-numberInput">', $source);
$event->setSource($sourceUpdated);
}
$event->addSnippet('ProductOption4/Resource/template/default/snippet.twig');
}
/**
* @param TemplateEvent $event
*/
public function adminProductIndexTemplateEvent(TemplateEvent $event)
{
$source = $event->getSource();
$source = str_replace('admin_product_export', 'admin_product_export_with_options', $source);
$source = str_replace('admin_product_product_delete', 'admin_product_product_delete_with_option', $source);
$event->setSource($source);
}
/**
* @param TemplateEvent $event
*/
public function adminProductTemplateEvent(TemplateEvent $event)
{
$source = $event->getSource();
#-- regex-replace an occurence by count
$counter = 1;
$s = preg_replace_callback('/<div class="card rounded border-0 mb-4"/', function ($m) use (&$counter) {
#-- replacement for 2nd occurence of "abc"
if ($counter++ == 3) {
return $this->getProductOptionSnipet() . '<div class="card rounded border-0 mb-4"';
}
#-- else leave current match
return $m[0];
}, $source);
$event->setSource($s);
/** @var Product $Product */
$event->addSnippet('@ProductOption4/admin/js.twig');
$parameters = $event->getParameters();
$parameters['params'] = [];
$event->setParameters($parameters);
}
/**
* @param TemplateEvent $event
*/
public function adminCsvProductTemplateEvent(TemplateEvent $event)
{
$source = $event->getSource();
$s = str_replace('admin_product_csv_import', 'admin_product_import_with_options', $source);
$event->setSource($s);
}
/**
* @param TemplateEvent $event
*/
public function adminOrderEditTemplateEvent(TemplateEvent $event)
{
$TargetOrder = null;
$OriginOrder = null;
$id = $this->request->get('id', null);
if (null === $id) {
return;
// 空のエンティティを作成.
$TargetOrder = new Order();
$TargetOrder->addShipping((new Shipping())->setOrder($TargetOrder));
$preOrderId = $this->orderHelper->createPreOrderId();
$TargetOrder->setPreOrderId($preOrderId);
} else {
$TargetOrder = $this->entityManager->getRepository(Order::class)->find($id);
if (null === $TargetOrder) {
throw new NotFoundHttpException();
}
}
// 編集前の受注情報を保持
$OriginOrder = clone $TargetOrder;
$OriginItems = new ArrayCollection();
foreach ($TargetOrder->getOrderItems() as $Item) {
$OriginItems->add($Item);
}
// get the product option items
$productOptionOrderItemGroups = $this->entityManager->getRepository(ProductOptionOrderItemGroup::class)
->findBy(array(
'order' => $TargetOrder,
));
$builder = $this->formFactory->createBuilder(OrderType::class, $TargetOrder);
$form = $builder->getForm();
$form->handleRequest($this->request);
$searchCustomerModalForm = $builder->getForm();
// 商品検索フォーム
$builder = $this->formFactory
->createBuilder(SearchProductType::class);
$searchProductModalForm = $builder->getForm();
// 配送業者のお届け時間
$times = [];
$deliveries = $this->entityManager->getRepository(Delivery::class)->findAll();
foreach ($deliveries as $Delivery) {
$deliveryTimes = $Delivery->getDeliveryTimes();
foreach ($deliveryTimes as $DeliveryTime) {
$times[$Delivery->getId()][$DeliveryTime->getId()] = $DeliveryTime->getDeliveryTime();
}
}
$data = [
'form' => $form->createView(),
'searchCustomerModalForm' => $searchCustomerModalForm->createView(),
'searchProductModalForm' => $searchProductModalForm->createView(),
'Order' => $TargetOrder,
'id' => $id,
'shippingDeliveryTimes' => $this->serializer->serialize($times, 'json'),
'productOptionOrderItemGroups' => $productOptionOrderItemGroups,
];
$source = $this->twigEngine->render('@ProductOption4/admin/order_edit.twig', $data);
$event->setSource($source);
}
public function adminEditComplete(EventArgs $event) {
$product = $event->getArgument('Product');
$request = $event->getRequest();
$allRequestData = $request->request->all();
$optionGroups = isset($allRequestData['optionGroup']) ? $allRequestData['optionGroup'] : null;
if ($optionGroups) {
$entityManager = $this->container->get('doctrine.orm.entity_manager');
$productOptionNameRepo = $entityManager->getRepository(ProductOptionName::class);
$productOptionNameRepo->resetProductOptionName($product);
$rank = 1;
foreach ($optionGroups as $optionGroup) {
$optionUid = $optionGroup['optionName']['id'];
$optionName = $optionGroup['optionName']['name'];
$isRequired = isset($optionGroup['optionName']['required']) ? $optionGroup['optionName']['required'] : 0;
$productOptionName = $productOptionNameRepo->findOneBy(['uid' => $optionUid]);
if (!$productOptionName) {
$productOptionName = new ProductOptionName();
}
$productOptionName->setUid($optionUid);
$productOptionName->setName($optionName);
$productOptionName->setRequired($isRequired);
$productOptionName->setProduct($product);
$productOptionName->setRank($rank);
if (isset($optionGroup['option'])) {
foreach ($optionGroup['option'] as $optionItemData) {
$name = $optionItemData['title'];
$optionItem = new ProductOptionCategory();
$optionItem->setName($name);
$optionItem->setRank($rank);
$visibleOption = $optionItemData['visible'] == 'true' ? true : false;
$optionItem->setVisible($visibleOption);
$optionItem->setPrice($optionItemData['price']);
$optionItem->setProductOptionName($productOptionName);
$optionItem->setCode($optionItemData['code']);
$entityManager->persist($optionItem);
$productOptionName->addProductOptionCategory($optionItem);
$rank++;
}
}
$entityManager->persist($productOptionName);
}
$entityManager->flush();
}
}
/**
* Insert the product option edit html here
* @return string
*/
private function getProductOptionSnipet() {
return $this->twigEngine->render('ProductOption4/Resource/template/admin/option-form.twig', []);
}
public function twigMypageHistory(TemplateEvent $event) {
$orderNo = $this->container->get('request_stack')->getMasterRequest()->get('order_no');
$Order = $this->entityManager->getRepository(Order::class)->find($orderNo);
$this->entityManager->getFilters()
->enable('incomplete_order_status_hidden');
$stockOrder = true;
foreach ($Order->getOrderItems() as $orderItem) {
if ($orderItem->isProduct() && $orderItem->getQuantity() < 0) {
$stockOrder = false;
break;
}
}
$productOptionOrderItemGroups = $this->entityManager->getRepository(ProductOptionOrderItemGroup::class)
->findBy(array(
'order' => $Order,
));
if (count($productOptionOrderItemGroups) === 0) {
return;
}
$data = [
'Order' => $Order,
'stockOrder' => $stockOrder,
'productOptionOrderItemGroups' => $productOptionOrderItemGroups,
];
$source = $this->twigEngine->render('ProductOption4/Resource/template/default/history.twig', $data);
$event->setSource($source);
}
/**
* Override the order index template
*
* @param TemplateEvent $event
*/
public function adminOrderIndexTemplateEvent(TemplateEvent $event) {
// original twig template path
// src/Eccube/Resource/template/admin/Order/index.twig
$source = $event->getSource();
// update the order export to new export route
$s = str_replace('admin_order_export_order', 'admin_order_export_order_with_option', $source);
// update to new route for export shipping
$s = str_replace('admin_order_export_shipping', 'admin_order_export_shipping_order_with_option', $s);
// update the email preview route
$s = str_replace('admin_shipping_preview_notify_mail', 'admin_shipping_preview_notify_mail_with_option', $s);
$s = str_replace('admin_shipping_notify_mail', 'admin_shipping_notify_mail_with_option', $s);
$event->setSource($s);
}
/**
* Override the order index template
*
* @param TemplateEvent $event
*/
public function adminOrderPdfTemplateEvent(TemplateEvent $event) {
// original twig template path
// src/Eccube/Resource/template/admin/Order/order_pdf.twig
$source = $event->getSource();
$s = str_replace('admin_order_pdf_download', 'admin_order_pdf_download_with_option', $source);
$event->setSource($s);
}
}