<?php
/*
* Plugin Name: JoolenDisplayPoints4
*
* Copyright(c) joolen inc. All Rights Reserved.
*
* https://www.joolen.co.jp/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Plugin\JoolenDisplayPoints4;
use Eccube\Common\EccubeConfig;
use Eccube\Entity\BaseInfo;
use Eccube\Entity\Cart;
use Eccube\Entity\CustomerFavoriteProduct;
use Eccube\Entity\Plugin;
use Eccube\Entity\Product;
use Eccube\Entity\ProductClass;
use Eccube\Event\TemplateEvent;
use Eccube\Repository\BaseInfoRepository;
use Eccube\Repository\PluginRepository;
use Knp\Component\Pager\Pagination\SlidingPagination;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class Event implements EventSubscriberInterface
{
/**
* @var BaseInfo
*/
protected $BaseInfo;
/**
* @var Plugin
*/
private $FixedPointPlugin;
/**
* @var Plugin
*/
private $NoPointPlugin;
/**
* @var string
*/
protected $app_template_default_path;
/**
* AddProductFixedPointProcessor constructor.
*
* @throws \Exception
*/
public function __construct(
EccubeConfig $eccubeConfig,
BaseInfoRepository $baseInfoRepository,
PluginRepository $pluginRepository
) {
$this->BaseInfo = $baseInfoRepository->get();
// 商品追加ポイント設定プラグインの情報を取得
$this->FixedPointPlugin = $pluginRepository->findOneBy([
'code' => 'JoolenFixedPointsForProduct4',
'enabled' => true,
]);
// ポイント対象外商品設定プラグインの情報を取得
$this->NoPointPlugin = $pluginRepository->findOneBy([
'code' => 'JoolenNoPointsForProduct4',
'enabled' => true,
]);
$this->app_template_default_path = $eccubeConfig['eccube_theme_front_dir'].'/JoolenDisplayPoints4/Resource/template/default';
}
/**
* @return array
*/
public static function getSubscribedEvents()
{
return [
// --------------
// Front
// --------------
'Product/list.twig' => 'onRenderProductList',
'Product/detail.twig' => 'onRenderProductDetail',
'Cart/index.twig' => 'onRenderCartIndex',
'Mypage/favorite.twig' => 'onRenderFavorite',
];
}
/**
* [フロント]商品一覧画面の描画
*/
public function onRenderProductList(TemplateEvent $event)
{
$datum = [];
/** @var SlidingPagination $Pagination */
$Pagination = $event->getParameter('pagination');
foreach ($Pagination->getItems() as $Product) {
$data = $this->getClassCategoriesAsJson($Product);
// MEMO: ポイントの最小と最大を求める
$pointRange = $this->calcPointRange($Product);
foreach ($pointRange as $key => $point) {
$data[$key] = $point;
}
// ポイント対象外商品設定プラグインが有効な場合、有効/無効のフラグを情報に追加する
$isNoPointFlag = false;
if ($this->NoPointPlugin) {
$isNoPointFlag = $Product->isNoPointFlag();
}
$data['is_no_point_flag'] = $isNoPointFlag;
$datum[$Product->getId()] = $data;
}
$twig = $this->getTwigPath('Product/list_js.twig');
$event->addAsset($twig);
$event->setParameter('display_point_json', json_encode($datum));
}
/**
* [フロント]商品詳細画面の描画
*/
public function onRenderProductDetail(TemplateEvent $event)
{
$datum = [];
/** @var Product $Product */
$Product = $event->getParameter('Product');
$data = $this->getClassCategoriesAsJson($Product);
// MEMO: ポイントの最小と最大を求める
$pointRange = $this->calcPointRange($Product);
foreach ($pointRange as $key => $point) {
$data[$key] = $point;
// ポイント対象外商品設定プラグインが有効な場合、有効/無効のフラグを情報に追加する
$isNoPointFlag = false;
if ($this->NoPointPlugin) {
$isNoPointFlag = $Product->isNoPointFlag();
}
$data['is_no_point_flag'] = $isNoPointFlag;
}
$datum[$Product->getId()] = $data;
$twig = $this->getTwigPath('Product/detail_js.twig');
$event->addAsset($twig);
$event->setParameter('display_point_json', json_encode($datum));
}
/**
* [フロント]カート画面の描画
*/
public function onRenderCartIndex(TemplateEvent $event)
{
$Carts = $event->getParameter('Carts');
$datum = [];
/** @var Cart $Cart */
foreach ($Carts as $Cart) {
foreach ($Cart->getCartItems() as $CartItem) {
$ProductClass = $CartItem->getProductClass();
// カート内の商品のポイントを合算する
$point = $this->calcPoint($ProductClass, $CartItem->getQuantity());
// ポイント対象外商品設定プラグインが有効な場合、有効/無効のフラグを情報に追加する
$isNoPointFlag = false;
if ($this->NoPointPlugin) {
$isNoPointFlag = $ProductClass->getProduct()->isNoPointFlag();
}
$datum[$CartItem->getId()] = [
'point' => $point,
'is_no_point_flag' => $isNoPointFlag,
];
}
}
$event->setParameter('cart_points', $datum);
}
/**
* [フロント]Mypage/お気に入り一覧画面の描画
*/
public function onRenderFavorite(TemplateEvent $event)
{
/** @var SlidingPagination $Pagination */
$Pagination = $event->getParameter('pagination');
$favoritePointRanges = [];
/** @var CustomerFavoriteProduct $CustomerFavoriteProduct */
foreach ($Pagination->getItems() as $CustomerFavoriteProduct) {
$Product = $CustomerFavoriteProduct->getProduct();
$favoritePointRanges[$Product->getId()] = $this->calcPointRange($CustomerFavoriteProduct->getProduct());
// ポイント対象外商品設定プラグインが有効な場合、有効/無効のフラグを情報に追加する
$isNoPointFlag = false;
if ($this->NoPointPlugin) {
$isNoPointFlag = $Product->isNoPointFlag();
}
$favoritePointRanges[$Product->getId()]['is_no_point_flag'] = $isNoPointFlag;
}
$event->setParameter('favorite_points', $favoritePointRanges);
}
/**
* Get the ClassCategories as JSON.
*
* @return \array[][]|string
*/
public function getClassCategoriesAsJson(Product $Product)
{
$Product->_calc();
$class_categories = [
'__unselected' => [
'__unselected' => [
'name' => trans('common.select'),
'product_class_id' => '',
],
],
];
foreach ($Product->getProductClasses() as $ProductClass) {
/** @var ProductClass $ProductClass */
if (!$ProductClass->isVisible()) {
continue;
}
/* @var $ProductClass \Eccube\Entity\ProductClass */
$ClassCategory1 = $ProductClass->getClassCategory1();
$ClassCategory2 = $ProductClass->getClassCategory2();
if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
continue;
}
$class_category_id1 = $ClassCategory1 ? (string) $ClassCategory1->getId() : '__unselected2';
$class_category_id2 = $ClassCategory2 ? (string) $ClassCategory2->getId() : '';
$class_categories[$class_category_id1]['#'] = [
'classcategory_id2' => '',
'name' => trans('common.select'),
'product_class_id' => '',
];
$class_categories[$class_category_id1]['#'.$class_category_id2] = [
'point' => $this->calcPoint($ProductClass),
];
}
return $class_categories;
}
/**
* 商品のポイントの最大と最小を計算して返します
*
* @return array|int[]
*/
private function calcPointRange(Product $Product)
{
$points = [];
foreach ($Product->getProductClasses() as $ProductClass) {
$points[] = $this->calcPoint($ProductClass);
}
return ['min_point' => min($points), 'max_point' => max($points)];
}
/**
* 規格ごとのポイントを計算して返します
*
* @return float|int
*/
private function calcPoint(ProductClass $ProductClass, $quantity = 1)
{
if (!$this->BaseInfo->isOptionPoint()) {
return 0;
}
$Product = $ProductClass->getProduct();
// ポイント対象外商品設定プラグインにより付与が無効の場合は0を返す
if ($this->NoPointPlugin) {
if ($Product->isNoPointFlag()) {
return 0;
}
}
$point = 0;
$pointRate = $this->BaseInfo->getBasicPointRate();
// MEMO: 基本のポイント計算
// ポイント = 単価 * ポイント付与率 * 数量
$point += round($ProductClass->getPrice02() * ($pointRate / 100)) * $quantity;
// MEMO: 商品追加ポイントプラグインで設定されているポイントを加算
if ($this->FixedPointPlugin) {
$point += $Product->getFixedPoint() * $quantity;
}
return $point;
}
/**
* 使用するTwigのパスを取得する
* app/template配下にある場合はそっちを優先
*
* @param $path
* @return string
*/
private function getTwigPath($path)
{
// MEMO: ページ管理で編集したテンプレートの保存先のパス
$app_template_default_path = $this->app_template_default_path.'/'.$path;
// MEMO: ページ管理で編集したテンプレートがある場合 優先してそっちを使う
if (file_exists($app_template_default_path)) {
return $app_template_default_path;
}
return '@JoolenFriendPoint4/default/'.$path;
}
}