<?php
/*
* UaGaEEc: Google Analytics eコマース/拡張eコマース対応プラグイン
* Copyright (C) 2016-2021 Freischtide Inc. All Rights Reserved.
* http://freischtide.tumblr.com/
*
* License: see LICENSE.txt
*/
namespace Plugin\UaGaEEc4;
use Eccube\Common\EccubeConfig;
use Eccube\Event\TemplateEvent;
use Eccube\Entity\Order;
use Plugin\UaGaEEc4\Entity\UaGaEEc;
use Plugin\UaGaEEc4\Repository\UaGaEEcRepository;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Finder\Finder;
class Event implements EventSubscriberInterface
{
/**
* @var UaGaEEcRepository
*/
private $repo;
/**
* @var EccubeConfig
*/
private $eccubeConfig;
/**
* @var TokenStorageInterface
*/
private $tokenStorage;
/**
* @var AuthorizationCheckerInterface
*/
private $authorizationChecker;
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var ContainerInterface
*/
private $container;
/**
* @var UaGaEEc
*/
private $uagaeec;
private $uagaeec_tag_rendered = false;
/**
* Event constructor.
* @param UaGaEEcRepository $repo
* @param EccubeConfig $eccubeConfig
* @param TokenStorageInterface $tokenStorage
* @param AuthorizationCheckerInterface $authorizationChecker
* @param RequestStack $requestStack
* @param ContainerInterface $container
* @param \Twig_Environment $environment
*/
public function __construct(
UaGaEEcRepository $repo,
EccubeConfig $eccubeConfig,
TokenStorageInterface $tokenStorage,
AuthorizationCheckerInterface $authorizationChecker,
RequestStack $requestStack,
ContainerInterface $container
) {
$this->repo = $repo;
$this->eccubeConfig = $eccubeConfig;
$this->tokenStorage = $tokenStorage;
$this->authorizationChecker = $authorizationChecker;
$this->requestStack = $requestStack;
$this->container = $container;
$this->uagaeec = $this->repo->get();
}
/**
* @return array
*/
public static function getSubscribedEvents()
{
$template_path = __DIR__ . '/../../../src/Eccube/Resource/template/default/';
$subscribed_events = [];
foreach ((new Finder())->in($template_path)->name('*.twig')->files() as $fileinfo) {
$subscribed_events[str_replace($template_path, '', $fileinfo->getPathname())] = 'all';
}
$subscribed_events['Product/list.twig'] = 'productList';
$subscribed_events['Mypage/favorite.twig'] = 'mypageFavorite';
$subscribed_events['Product/detail.twig'] = 'productDetail';
$subscribed_events['Cart/index.twig'] = 'cart';
$subscribed_events['Shopping/login.twig'] = 'shopping_login';
$subscribed_events['Shopping/nonmember.twig'] = 'shopping_nonmember';
$subscribed_events['Shopping/index.twig'] = 'shopping';
$subscribed_events['Shopping/confirm.twig'] = 'shopping';
$subscribed_events['Shopping/complete.twig'] = 'shoppingComplete';
return $subscribed_events;
}
private function setVars(&$parameters)
{
if ($this->uagaeec->getTrackUserId() == UaGaEEc::UAGAEEC_OP_INCLUDE_USER_ID) {
if (!is_null($this->tokenStorage->getToken()) &&
$this->authorizationChecker->isGranted('ROLE_USER')) {
$customer_id = $this->tokenStorage->getToken()->getUser()->getId();
$parameters['user_id'] = $this->getUuid5($this->eccubeConfig->get('UAGAEEC_UUID'),
$this->uagaeec->getTid(),
$customer_id);
}
}
if ($crossdomain_linker = $this->uagaeec->getCrossdomainLinker()) {
$autoLinks = explode(',', $crossdomain_linker);
foreach ($autoLinks as $key => $value) {
// $autoLinks[$key] = '"' . (trim(str_replace('"','',$value))) . '"'; // Escape javascript and add '"' to each domain
$autoLinks[$key] = "'" . (trim(str_replace("'","",$value))) . "'"; // Escape javascript and add '"' to each domain
}
$parameters['crossdomain_linker'] = implode(',', $autoLinks);
}
$pid = $this->requestStack->getCurrentRequest()->get('ugep_id');
$pname = $this->requestStack->getCurrentRequest()->get('ugep_name');
if ($pid && $pname) {
$promo['id'] = addslashes($pid);
$promo['name'] = addslashes($pname);
$promo['creative'] = addslashes($this->requestStack->getCurrentRequest()->get('ugep_creative'));
$promo['position'] = addslashes($this->requestStack->getCurrentRequest()->get('ugep_position'));
$parameters['promo'] = $promo;
}
}
public function all(TemplateEvent $event)
{
$tid = $this->uagaeec->getTid();
if (empty($tid)) {
return;
}
if ($this->uagaeec_tag_rendered) {
return;
}
$parameters = $event->getParameters();
$this->setVars($parameters);
$parameters['uagaeec'] = $this->uagaeec;
$parameters['partial'] = '@UaGaEEc4/default/_all.twig';
$event->setParameters($parameters);
$this->addAsset($event);
}
public function productList(TemplateEvent $event)
{
$tid = $this->uagaeec->getTid();
if (empty($tid)) {
return;
}
if ($this->uagaeec->getEec() == UaGaEEc::UAGAEEC_USE_EC ||
$this->requestStack->getCurrentRequest()->getMethod() != 'GET') {
$this->all($event);
return;
}
$parameters = $event->getParameters();
$this->setVars($parameters);
$name = $this->requestStack->getCurrentRequest()->get('name');
if (!empty($name)) {
$list = 'Search Results';
} else {
$list = 'Category List';
}
$items = $parameters['pagination']->getItems();
$impressions = [];
if ($this->uagaeec->getImpTrack() == UaGaEEc::UAGAEEC_OP_WITH_IMP_TRACK) {
if ($this->uagaeec->getCategory() == UaGaEEc::UAGAEEC_OP_CATEGORY_ON &&
is_object($parameters['Category'])) {
$category = $parameters['Category']->getName();
} else {
$category = '';
}
foreach ($items as $item) {
$impressions[] = $this->buildEcImpression($item, $list, $category);
}
}
$parameters['uagaeec'] = $this->uagaeec;
$parameters['impressions'] = $impressions;
$parameters['partial'] = '@UaGaEEc4/default/_product_list.twig';
$parameters['list_name'] = $list;
$event->setParameters($parameters);
$this->addAsset($event);
}
public function mypageFavorite(TemplateEvent $event)
{
$tid = $this->uagaeec->getTid();
if (empty($tid)) {
return;
}
if ($this->uagaeec->getEec() == UaGaEEc::UAGAEEC_USE_EC ||
$this->requestStack->getCurrentRequest()->getMethod() != 'GET') {
$this->all($event);
return;
}
$parameters = $event->getParameters();
$this->setVars($parameters);
$list = 'Favorite List';
$items = $parameters['pagination']->getItems();
$impressions = [];
if ($this->uagaeec->getImpTrack() == UaGaEEc::UAGAEEC_OP_WITH_IMP_TRACK) {
foreach ($items as $item) {
// CustomerFavoriteProduct => Product
$product = $item->getProduct($item->getId());
$category = $this->getCategory($product);
$impressions[] = $this->buildEcImpression($product, $list, $category);
}
}
$parameters['uagaeec'] = $this->uagaeec;
$parameters['impressions'] = $impressions;
$parameters['partial'] = '@UaGaEEc4/default/_product_list.twig';
$parameters['list_name'] = $list;
$event->setParameters($parameters);
$this->addAsset($event);
}
public function productDetail(TemplateEvent $event)
{
$tid = $this->uagaeec->getTid();
if (empty($tid)) {
return;
}
if ($this->uagaeec->getEec() == UaGaEEc::UAGAEEC_USE_EC ||
$this->requestStack->getCurrentRequest()->getMethod() != 'GET') {
$this->all($event);
return;
}
$parameters = $event->getParameters();
$this->setVars($parameters);
$list = 'Item Detail';
$product = $parameters['Product'];
$category = $this->getCategory($product);
$products = [$this->buildEcProduct($product, $category)];
$action = ['action' => 'detail', 'option' => ''];
$clickFrom = $this->decideList($_SERVER);
if ($clickFrom != 'Direct Access') {
$this->uagaeec->setClick($this->getOptionsStr(['list' => json_encode($clickFrom)]));
}
$impressions = [];
if ($this->uagaeec->getImpTrack() == UaGaEEc::UAGAEEC_OP_WITH_IMP_TRACK) {
// related product from RelatedProduct plugin by EC-CUBE
// https://github.com/EC-CUBE/related-product-plugin
if (class_exists('Plugin\RelatedProduct4\Entity\RelatedProduct')) {
$relatedProductPlugin = false;
$enabledPlugins = $this->container->getParameter('eccube.plugins.enabled');
foreach ($enabledPlugins as $plugin) {
if ($plugin == 'RelatedProduct4') {
$relatedProductPlugin = true;
break;
}
}
if ($relatedProductPlugin) {
foreach ($product->getRelatedProducts() as $relatedProduct) {
$childProduct = $relatedProduct->getChildProduct();
if ($childProduct->getStatus()->getId() == \Eccube\Entity\Master\ProductStatus::DISPLAY_SHOW) {
$childCategory = $this->getCategory($childProduct);
$impressions[] = $this->buildEcImpression($childProduct, $list, $childCategory);
}
}
}
}
}
$parameters['uagaeec'] = $this->uagaeec;
$parameters['impressions'] = $impressions;
$parameters['products'] = $products;
$parameters['action'] = $action;
$parameters['partial'] = '@UaGaEEc4/default/_product_detail.twig';
$parameters['list_name'] = $clickFrom;
$event->setParameters($parameters);
$this->addAsset($event);
}
public function cart(TemplateEvent $event)
{
$tid = $this->uagaeec->getTid();
if (empty($tid)) {
return;
}
if ($this->uagaeec->getEec() == UaGaEEc::UAGAEEC_USE_EC ||
$this->requestStack->getCurrentRequest()->getMethod() != 'GET') {
$this->all($event);
return;
}
$parameters = $event->getParameters();
$this->setVars($parameters);
$carts = $parameters['Carts'];
$products = array();
foreach ($carts as $cart) {
foreach ($cart->getCartItems() as $cartItem) {
$product = $cartItem->getProductClass()->getProduct();
$category = $this->getCategory($product);
$products[] = $this->buildEcProduct($product,
$category,
$cartItem->getPrice(),
$cartItem->getQuantity());
}
}
$action = ['action' => 'add', 'option' => ''];
$parameters['uagaeec'] = $this->uagaeec;
$parameters['products'] = $products;
$parameters['action'] = $action;
$parameters['partial'] = '@UaGaEEc4/default/_cart.twig';
$event->setParameters($parameters);
$this->addAsset($event);
}
// 買い物時のログイン
public function shopping_login(TemplateEvent $event)
{
$tid = $this->uagaeec->getTid();
if (empty($tid)) {
return;
}
if ($this->uagaeec->getEec() == UaGaEEc::UAGAEEC_USE_EC ||
$this->requestStack->getCurrentRequest()->getMethod() != 'GET') {
$this->all($event);
return;
}
$parameters = $event->getParameters();
$this->setVars($parameters);
//$action = ['action' => 'checkout', 'option' => $this->getOptionsStr([
// 'step' => 1 // ログイン
//])];
$parameters['uagaeec'] = $this->uagaeec;
//$parameters['action'] = $action;
//$parameters['partial'] = '@UaGaEEc4/default/_shopping.twig';
$parameters['partial'] = '@UaGaEEc4/default/_all.twig';
//$parameters['event'] = 'begin_checkout';
//$parameters['checkout_step'] = 1;
$event->setParameters($parameters);
$this->addAsset($event);
}
// お客様情報
public function shopping_nonmember(TemplateEvent $event)
{
$tid = $this->uagaeec->getTid();
if (empty($tid)) {
return;
}
if ($this->uagaeec->getEec() == UaGaEEc::UAGAEEC_USE_EC ||
$this->requestStack->getCurrentRequest()->getMethod() != 'GET') {
$this->all($event);
return;
}
$parameters = $event->getParameters();
$this->setVars($parameters);
//$action = ['action' => 'checkout', 'option' => $this->getOptionsStr([
// 'step' => 2 // お客様情報
//])];
$parameters['uagaeec'] = $this->uagaeec;
//$parameters['action'] = $action;
//$parameters['partial'] = '@UaGaEEc4/default/_shopping.twig';
$parameters['partial'] = '@UaGaEEc4/default/_all.twig';
//$parameters['event'] = 'checkout_progress';
//$parameters['checkout_step'] = 2;
$event->setParameters($parameters);
$this->addAsset($event);
}
// step 1: ご注文手続き(GET), step 2: ご注文内容確認(POST)
public function shopping(TemplateEvent $event)
{
$tid = $this->uagaeec->getTid();
if (empty($tid)) {
return;
}
if ($this->uagaeec->getEec() == UaGaEEc::UAGAEEC_USE_EC) {
if ($this->requestStack->getCurrentRequest()->getMethod() == 'POST' &&
$this->uagaeec->getConfirmationAsPurchase() == UaGaEEc::UAGAEEC_OP_CONFIRMATION_AS_PURCHASE) {
# confirmation as purchase
} else {
$this->all($event);
return;
}
}
$parameters = $event->getParameters();
$this->setVars($parameters);
// order id を一時的に保持(ペイジェント等の外部決済システムが order id を返さないため)
$order = $parameters['Order'];
if ($order->getId()) {
$cookie = isset($_COOKIE['eccube_uagaeec']) ? json_decode($_COOKIE['eccube_uagaeec'], true) : [];
$cookie['orderId'] = $order->getId();
setcookie('eccube_uagaeec', json_encode($cookie), time()+60*60, '/');
}
$orderDetails = $order->getOrderItems();
$products = [];
foreach ($orderDetails as $orderDetail) {
if (!$orderDetail->isProduct()) {
continue;
}
$product = $orderDetail->getProduct();
$category = $this->getCategory($product);
$products[] = $this->buildEcProduct($product,
$category,
$orderDetail->getPriceIncTax(),
$orderDetail->getQuantity());
}
$action = ['action' => 'checkout', 'option' => $this->getOptionsStr([
//'step' => $this->requestStack->getCurrentRequest()->getMethod() == 'POST' ? 4 : 3,
'step' => $this->requestStack->getCurrentRequest()->getMethod() == 'POST' ? 2 : 1,
//'option' => '"' . $orderDetail['Order']['payment_method'] . '"'
])];
$parameters['uagaeec'] = $this->uagaeec;
$parameters['products'] = $products;
$parameters['action'] = $action;
$parameters['partial'] = '@UaGaEEc4/default/_shopping.twig';
//$parameters['event'] = 'checkout_progress';
//$parameters['checkout_step'] = $this->requestStack->getCurrentRequest()->getMethod() == 'POST' ? 4 : 3;
$parameters['event'] = 'begin_checkout';
$parameters['checkout_step'] = 1;
if ($this->requestStack->getCurrentRequest()->getMethod() == 'POST') {
$parameters['event'] = 'checkout_progress';
$parameters['checkout_step'] = 2;
if ($this->uagaeec->getConfirmationAsPurchase() == UaGaEEc::UAGAEEC_OP_CONFIRMATION_AS_PURCHASE) {
$parameters['transaction'] = $this->getTransaction($order);
$parameters['order'] = $order;
# eコマースの場合はテンプレートを置きかえる
if ($this->uagaeec->getEec() == UaGaEEc::UAGAEEC_USE_EC) {
$parameters['partial'] = '@UaGaEEc4/default/_shopping_complete.twig';
}
}
}
$event->setParameters($parameters);
$this->addAsset($event);
}
public function shoppingComplete(TemplateEvent $event)
{
$tid = $this->uagaeec->getTid();
if (empty($tid)) {
return;
}
if ($this->uagaeec->getConfirmationAsPurchase() == UaGaEEc::UAGAEEC_OP_CONFIRMATION_AS_PURCHASE) {
return;
}
if ($this->requestStack->getCurrentRequest()->getMethod() != 'GET') {
$this->all($event);
return;
}
$parameters = $event->getParameters();
$this->setVars($parameters);
// 必要に応じて cookie より order id を復元
$order = $parameters['Order'];
if (empty($order)) {
$cookie = isset($_COOKIE['eccube_uagaeec']) ? json_decode($_COOKIE['eccube_uagaeec'], true) : [];
if (isset($cookie['orderId'])) {
$orderId = $cookie['orderId'];
$entityManager = $this->container->get('doctrine')->getManager();
$orderRepository = $entityManager->getRepository(Order::class);
$order = $orderRepository->find($orderId);
unset($cookie['orderId']);
setcookie('eccube_uagaeec', json_encode($cookie), time()+60*60, '/');
} else {
return;
}
}
$orderDetails = $order->getOrderItems();
$products = [];
foreach ($orderDetails as $orderDetail) {
if (!$orderDetail->isProduct()) {
continue;
}
$product = $orderDetail->getProduct();
$category = $this->getCategory($product);
$products[] = $this->buildEcProduct($product,
$category,
$orderDetail->getPriceIncTax(),
$orderDetail->getQuantity());
}
$transaction = $this->getTransaction($order);
$action = ['action' => 'purchase', 'option' => $this->getOptionsStr($transaction)];
$parameters['uagaeec'] = $this->uagaeec;
$parameters['products'] = $products;
$parameters['action'] = $action;
$parameters['transaction'] = $transaction;
$parameters['partial'] = '@UaGaEEc4/default/_shopping_complete.twig';
$parameters['order'] = $order;
$event->setParameters($parameters);
$this->addAsset($event);
}
private function addAsset($event)
{
if ($this->uagaeec->getGaGtag() == UaGaEEc::UAGAEEC_USE_GA) {
$event->addAsset('@UaGaEEc4/default/uagaeec.twig');
} elseif ($this->uagaeec->getGaGtag() == UaGaEEc::UAGAEEC_USE_GTAG) {
$event->addAsset('@UaGaEEc4/default/uagaeec_gtag.twig');
}
$this->uagaeec_tag_rendered = true;
}
private function getCategory($product)
{
$category = '';
if ($this->uagaeec->getCategory() == UaGaEEc::UAGAEEC_OP_CATEGORY_ON) {
$productCategories = $product->getProductCategories();
$categories = array();
foreach ($productCategories as $productCategory) {
$categories[] = $productCategory['Category']->getName();
}
$category = implode('/', $categories);
}
return $category;
}
private function getOptionsStr($options)
{
$results = array();
foreach ($options as $k => $v) {
$results[] = "'" . $k . "': " . $v;
}
return implode(', ', $results);
}
private function decideList($serverEnv)
{
if(!empty($serverEnv['HTTP_REFERER'])) {
$referrer = $serverEnv['HTTP_REFERER'];
} else {
return 'Direct Access';
}
$url = parse_url($referrer);
if ($url['host'] == $serverEnv['SERVER_NAME']) {
switch (true) {
case $url['path'] == '/':
return 'TOP';
case stristr($url['path'], '/mypage/favorite'):
return 'Favorite List';
case stristr($url['path'], '/products/list'):
$name = $this->requestStack->getCurrentRequest()->get('name');
if (!empty($name)) {
return 'Search Results';
} else {
return 'Category List';
}
case stristr($url['path'], '/products/detail'):
return 'Item Detail';
default:
return 'Internal Site';
}
} else {
if ($this->uagaeec->getUseCustomReferrer() == UaGaEEc::UAGAEEC_OP_USE_CUSTOM_REFERRER) {
foreach ($this->uagaeec->getCustomReferrers() as $customer_referrer) {
if (stristr($referrer, $customer_referrer[0])) {
return addslashes($customer_referrer[1]);
}
}
}
return 'External Site';
}
}
private function getTransaction($order)
{
$transaction = [
'id' => "'" . $order['id'] . "'",
'revenue' => "'" . $order['total'] . "'",
'tax' => "'" . $order['tax'] . "'",
'shipping' => "'" . $order['delivery_fee_total'] . "'"
];
return $transaction;
}
private function getUuid5($namespace_id, $ga_tid, $customer_id)
{
$customer_hash = sha1($namespace_id . $ga_tid . $customer_id);
$time_low = substr($customer_hash, 0, 8);
$time_mid = substr($customer_hash, 8, 4);
$time_hi_and_version = substr($customer_hash, 12, 4);
$time_hi_and_version = sprintf('%04x', (intval('0x' . $time_hi_and_version, 16) & 0x0fff) | 0x3000);
$clk_seq_hi_res = substr($customer_hash, 16, 2);
$clk_seq_hi_res = sprintf('%02x', (intval('0x' . $clk_seq_hi_res, 16) & 0x3f) | 0x80);
$clk_seq_low = substr($customer_hash, 18, 2);
$node = substr($customer_hash, 20, 12);
return sprintf('%8s-%4s-%4s-%2s%2s-%12s', $time_low, $time_mid, $time_hi_and_version, $clk_seq_hi_res, $clk_seq_low, $node);
}
private function buildEcImpression($item, $list, $category)
{
return array('id' => $item->getId(),
'name' => addslashes($item->getName()),
'list' => $list,
'category' => addslashes($category),
'price' => $item->getPrice02IncTaxMax());
}
private function buildEcProduct($product, $category, $price = null, $quantity = 0)
{
return array('id' => $product->getId(),
'name' => addslashes($product->getName()),
'price' => $price == null ? $product->getPrice02IncTaxMax() : $price,
'quantity' => $quantity,
'category' => addslashes($category));
}
}