<?php
/*
* 「この商品を見た人はこんな商品も見ています」プラグイン(EC-CUBE4系)
* 2021/05/16 Ver.1.0.7 前バージョン
* 2021/05/18 Ver.1.0.8 商品固有の税率で価格を表示するようにした。
* 2021/05/26 Ver.1.0.9 「最低価格~最高価格」の表示で正しく税込み表示できるようにした。
*/
namespace Plugin\HsdRelatedProduct42\Controller\Block;
use Eccube\Controller\AbstractController;
use Plugin\HsdRelatedProduct42\Repository\ConfigRepository;
use Plugin\HsdRelatedProduct42\Entity\HsdRelatedProduct42;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use \PDO;
class HsdRelatedProduct42Controller extends AbstractController
{
// タイトル
private $_title = 'この商品をみた人はこんな商品もみています';
private $_show_count = 4; // 表示個数(初期値4)
private $_rp = []; // 関連商品用データ
private $_show_price = 'true'; // 価格の表示/非表示
private $_show_type = 'normal'; // 表示タイプ(初期値 スライダーなし)
private $_pagination = 'true'; // ページネーション(初期値 あり
private $_navbuttons = 'true'; // ナビゲーション(初期値 あり
private $_showloop = 'true'; // 表示の自動ループ//初期値 あり
private $_calc_rule = 'round'; // 税率の計算方法// 四捨五入(デフォルト)
private $_tax = 1.10; // 税率(初期値10%)
// Anna用
private $_save_from_id = 0;
private $_save_to_id = 0;
private $_save_from_product_name = '';
private $_save_to_product_name = '';
private $_def_max_row = 1000; //データの最大保持数の初期値
/**
* HsdRelatedProduct42Controller constructor.
*
* @param ConfigRepository $configRepository
*/
public function __construct(ConfigRepository $configRepository, RequestStack $requestStack)
{
$this->_configRepository = $configRepository;
$this->requestStack = $requestStack;
}
/**
* @Route("block_hsd_related_product42", name="block_hsd_related_product42")
* @Template("@Block/hsd_related_product42.twig")
*/
public function index(Request $request)
{
// データベースハンドルを取得
$dbh = $this->entityManager->getConnection();
// 真ならPostgrSQL偽ならMySQLを表すフラグを用意
$isPostgreSQL = $dbh->getDatabasePlatform()->getName() == 'postgresql';
/*
* 詳細画面の場合のみ動作
* /products/detail/[product_id] を想定
*/
$request_stack = $this->get('request_stack')->getMasterRequest();
$chkpath = explode('/', $request_stack->getPathInfo());
if ( $chkpath[1] == 'products' && $chkpath[2] == 'detail' ) {
$id = $chkpath[3]; //現在表示中のメインの商品ID
$max_row = $this->_def_max_row; // 初期値1000
// 保持する最大データ数を取得し、1回の削除数を設定(20%を設定)
$setting = $this->_configRepository->get();
if( $setting != null ){
if( !empty($setting->getMaxNum()) && is_numeric($setting->getMaxNum()) ) {
$this->_show_count = $setting->getMaxNum();
}
if( !empty($setting->getMaxRowNum()) && is_numeric($setting->getMaxRowNum()) ) {
$max_row = $setting->getMaxRowNum();
$del_rows = intval($max_row * 0.2);
}else{
$del_rows = 200;
}
if( !empty($setting->getTitle()) ) {
$this->_title = $setting->getTitle();
}
if( !empty($setting->getShowPrice()) ) {
$this->_show_price = $setting->getShowPrice();
}
if( !empty($setting->getShowType()) ) {
$this->_show_type = $setting->getShowType();
}
if( !empty($setting->getPagination()) ) {
$this->_pagination = $setting->getPagination();
}
if( !empty($setting->getNavbuttons()) ) {
$this->_navbuttons = $setting->getNavbuttons();
}
if( !empty($setting->getShowloop()) ) {
$this->_showloop = $setting->getShowloop();
}
}
$em = $this->entityManager;
$con_db_type = $em->getConnection()->getDatabasePlatform()->getName(); // postgresql or mysql
// データ保持数に達していたら削除
//$rs = $dbh->query( 'SELECT COUNT(id) FROM plg_hsd_related_product' )->fetchColumn();
$rs_tmp = $dbh->executeQuery( 'SELECT COUNT(id) as count FROM plg_hsd_related_product' )->fetchAllAssociative();
$rs = $rs_tmp[0]['count'];
if ( $rs > $max_row ) {
$del_rows = $rs - $max_row;
if( $con_db_type == 'postgresql' ){
$stmt = $dbh->executeQuery( 'DELETE FROM plg_hsd_related_product WHERE id IN ( SELECT id FROM plg_hsd_related_product ORDER BY updated_at ASC LIMIT '. $del_rows . ')' );
}else{
$stmt = $dbh->executeQuery( 'DELETE FROM plg_hsd_related_product ORDER BY updated_at ASC LIMIT '. $del_rows );
}
}
/*
* もしセッションにsave_pr_idが保持されていたら処理を行う
*/
if ( isset( $_SESSION['ec_save_pr_id'] ) ) {
$_from_id = $_SESSION['ec_save_pr_id'];
// DB更新:もしfromとtoが異なる場合は保持
if ( $_from_id != $id ) {
$rp_obj = new HsdRelatedProduct42();
$rp_obj->setId( uniqid('rp_') )
->setFromId( $_from_id )
->setToId( $id )
->setUpdatedAt( new \DateTime() );
$em->persist( $rp_obj );
$em->flush( $rp_obj );
}
}
// 現在の商品IDをもとに、次の商品IDを取得
$stmt = $dbh->prepare("SELECT count(rp.to_id) cn, rp.to_id FROM plg_hsd_related_product rp, dtb_product as p WHERE rp.from_id=:id AND rp.to_id = p.id AND p.product_status_id = 1 GROUP BY rp.from_id, rp.to_id ORDER BY cn DESC");
$stmt->bindValue( ':id', $id, PDO::PARAM_INT );
$stex = $stmt->executeQuery();
$rs = $stex->fetchAllAssociative();
// 関連商品自動表示ブロックの設定
$or_str = '';
foreach ( $rs as $item ){
$or_str .= '(ecp.id=' . $item['to_id'] . ' AND ecp.id = ecpi.product_id) or ';
}
$or_str = substr( $or_str, 0, strlen($or_str)-4 );
$rps = [];
if ( strlen( $or_str ) > 1 ) {
//$sql = 'SELECT ecp.id, ecp.name, ecp.description_detail, (SELECT in_ecpi.file_name FROM dtb_product_image in_ecpi WHERE in_ecpi.product_id = ecp.id AND in_ecpi.sort_no < 2 ) file_name, (SELECT MIN(in_pcl.price02) FROM dtb_product_class in_pcl WHERE in_pcl.product_id = ecp.id and in_pcl.visible = :visible GROUP BY in_pcl.product_id) min_price, (SELECT MAX(in_pcl.price02) FROM dtb_product_class in_pcl WHERE in_pcl.product_id = ecp.id and in_pcl.visible = :visible GROUP BY in_pcl.product_id) max_price FROM dtb_product ecp, dtb_product_image ecpi WHERE ' . $or_str . ' GROUP BY ecp.id';
$sql = 'SELECT ecp.id, ecp.name, ecp.description_detail, (SELECT in_ecpi.file_name FROM dtb_product_image in_ecpi WHERE in_ecpi.product_id = ecp.id AND in_ecpi.sort_no < 2 ORDER BY in_ecpi.sort_no ASC LIMIT 1 ) file_name, (SELECT MIN(in_pcl.price02) FROM dtb_product_class in_pcl WHERE in_pcl.product_id = ecp.id and in_pcl.visible = :visible GROUP BY in_pcl.product_id) min_price, (SELECT MAX(in_pcl.price02) FROM dtb_product_class in_pcl WHERE in_pcl.product_id = ecp.id and in_pcl.visible = :visible GROUP BY in_pcl.product_id) max_price FROM dtb_product ecp, dtb_product_image ecpi WHERE ' . $or_str . ' GROUP BY ecp.id';
$stmt = $dbh->prepare( $sql );
if ( $isPostgreSQL ) {
$stmt->bindValue( ':visible', true, PDO::PARAM_BOOL );
} else {
$stmt->bindValue( ':visible', 1, PDO::PARAM_INT );
}
$stex = $stmt->executeQuery();
$rps = $stex->fetchAllAssociative(); //該当商品リストが求まる
}
//log_info( print_r($rps,true));
//「店舗設定」の税率をDBから取得できないときのデフォルトを設定
$default_tax_rate = $this->_tax * 100 - 100;
$default_rounding_type_id = 1;
$calc_rule = [ 1 => 'round', //四捨五入
2 => 'floor', //切り捨て
3 => 'ceil' ]; //切り上げ
//DBに「店舗設定」の税率と、税率計算における丸めロジックを問い合わせる
$sql = "SELECT tax_rate,rounding_type_id FROM dtb_tax_rule WHERE id = 1";
$rs_tmp = $dbh->executeQuery( $sql )->fetchAllAssociative();
$default_tax_rate = $rs_tmp[0]['tax_rate'];
$default_rounding_type_id = $rs_tmp[0]['rounding_type_id'];
//list ( $default_tax_rate, $default_rounding_type_id ) = $dbh->query( $sql )->fetch( PDO::FETCH_NUM );
if ( $calc_rule[ $default_rounding_type_id ] === "" ) {
log_error( 'rounding_type_idが想定外の値です : '. $default_rounding_type_id );
exit;
}
// 商品ごとに税率と計算方法を取得して商品データ($rps)に追加する
for ( $i = 0; $i < count( $rps ); $i++ ) {
$product_id = $rps[$i]['id'];
if ( $rps[$i]['min_price'] != $rps[$i]['max_price'] ) {
// 商品規格が定義されている商品で「○○円~○○○円」といった表示が必要な場合
$sql = "SELECT tax_rate FROM dtb_tax_rule "
. "WHERE product_class_id IN ( "
. "SELECT id FROM dtb_product_class WHERE product_id = $product_id AND price02 = ? ) ORDER BY tax_rate ";
// tax_rule表から該当商品中でもっとも低く設定されている税率を取得する。
$stmt = $dbh->prepare( $sql ."ASC" );
$stmt->bindValue( 1, $rps[$i]['min_price'], PDO::PARAM_STR );
$stex = $stmt->executeQuery();
$min_rate_tmp = $stex->fetchAllAssociative(); // tax_rateは''か0~100の整数が返る。nullは無い。
$min_rate = $min_rate_tmp[0]['tax_rate'];
// tax_rule表から該当商品中でもっとも高く設定されている税率を取得する。
$stmt = $dbh->prepare( $sql ."DESC" );
$stmt->bindValue( 1, $rps[$i]['max_price'], PDO::PARAM_STR );
$stex = $stmt->executeQuery();
$max_rate_tmp = $stex->fetchAllAssociative(); // ''か0~100の整数が返る。nullは無い。
$max_rate = $max_rate_tmp[0]['tax_rate'];
// dtb_tax_rule表に商品規格が登録され販売価格は設定されていても税率欄は空ということがある。そのときはデフォルトの税率を採用する。
if ( ! is_numeric( $min_rate ) ) {
$min_rate = $default_tax_rate;
}
if ( ! is_numeric( $max_rate ) ) {
$max_rate = $default_tax_rate;
}
//log_info( "min_rate = '$min_rate', max_rate = '$max_rate'" );
// 商品データに、求まった税率を追加
$rps[$i]['tax'] = 1.0 + $min_rate / 100;
$rps[$i]['tax2'] = 1.0 + $max_rate / 100;
} else {
// 「商品規格」を設定していない商品(たいていは未設定)はこっちの処理を通る
// tax_rule表から税率が取得できないときはデフォルト値を使う
//$rps[$i]['tax'] = 1.0 + $default_tax_rate / 100;
$min_tax_rate = 0;
$min_tax_rate_tmp = $dbh->executeQuery(
"SELECT MIN(tax_rate) AS min_tax_rate FROM dtb_tax_rule WHERE product_id = $product_id" )->fetchAllAssociative();
$min_tax_rate = $min_tax_rate_tmp[0]['min_tax_rate'];
if ( $min_tax_rate > 0 ) {
// 税率と計算ルールが取得できたときは商品データにセットする。
$stmt = $dbh->executeQuery( "SELECT DISTINCT rounding_type_id FROM dtb_tax_rule WHERE product_id = $product_id" );
if ( $stmt->rowCount() >= 2 ) {
log_error( '同じproduct_idをもつ商品は皆同じrounding_type_idを持つことを期待しているのですが、'
. $stmt->rowCount() . '種類のrounding_type_idが検出されました。');
exit;
}
$st_tmp = $stmt->fetchAllAssociative();
$rounding_type_id = $st_tmp[0]['rounding_type_id'];
if ( $calc_rule[ $rounding_type_id ] === "" ) {
log_error('rounding_type_idが想定外の値です : '. $rounding_type_id );
exit;
}
$rps[$i]['tax'] = 1.0 + $min_tax_rate / 100;
$rps[$i]['calc_rule'] = $calc_rule[ $rounding_type_id ];
} else {
// 税率と計算ルールが取得できないときは商品データにデフォルト値をセットする。
$rps[$i]['tax'] = 1.0 + $default_tax_rate / 100;
$rps[$i]['calc_rule'] = $calc_rule[ $default_rounding_type_id ];
}
}
// 丸めロジックは全商品共通
$rps[$i]['calc_rule'] = $calc_rule[ $default_rounding_type_id ];
}
$this->_rp = $rps;
//log_info( print_r($rps,true));
$_SESSION['ec_save_pr_id'] = $id; // 現在の商品id をセッションに保持
}
return $this->render("Block/hsd_related_product42.twig",
[
'title' => $this->_title,
'max_count' => $this->_show_count,
'rp_count' => count($this->_rp),
'hsd_related_product' => $this->_rp,
'show_price' => $this->_show_price,
'show_type' => $this->_show_type,
'pagination' => $this->_pagination,
'navbuttons' => $this->_navbuttons,
'showloop' => $this->_showloop,
'from_id' => $this->_save_from_id,
'from_product_name' => $this->_save_from_product_name,
'to_id' => $this->_save_to_id,
'to_product_name' => $this->_save_to_product_name,
'calc_rule' => $this->_calc_rule
//'tax' => $this->_tax
] );
}
}