<?php
namespace Plugin\NZCategoryLayoutManager42\EventSubscriber;
use Eccube\Event\TemplateEvent;
use Plugin\NZCategoryLayoutManager42\Repository\CategoryLayoutRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class TemplateEventSubscriber implements EventSubscriberInterface
{
private $categoryLayoutRepository;
private $requestStack;
public function __construct(CategoryLayoutRepository $categoryLayoutRepository, RequestStack $requestStack)
{
$this->categoryLayoutRepository = $categoryLayoutRepository;
$this->requestStack = $requestStack;
}
public static function getSubscribedEvents()
{
return ['Product/list.twig' => 'onProductList'];
}
public function onProductList(TemplateEvent $event)
{
$request = $this->requestStack->getCurrentRequest();
if (!$request) {
return;
}
$categoryId = $request->query->get('category_id');
if (!$categoryId) {
return;
}
try {
$layout = $this->categoryLayoutRepository->findActiveByParentCategoryId((int)$categoryId);
if (!$layout) {
return;
}
$items = $layout->getCategoryLayoutItems();
if (!$items || $items->count() === 0) {
return;
}
// 子カテゴリ情報を構築
$gameCategories = [];
foreach ($items as $item) {
$gameCategories[] = [
'id' => (int)$item->getChildCategoryId(),
'name' => $item->getDisplayName(),
'icon' => $item->getIconPath() ?: ''
];
}
$gameCategoriesJson = json_encode($gameCategories, JSON_UNESCAPED_UNICODE);
// CSS
$event->addSnippet('<style>
.game-category-parent-layout{width:100%;padding:20px 0}
.game-section{margin-bottom:60px;padding-bottom:40px;border-bottom:2px solid #e0e0e0}
.game-section:last-child{border-bottom:none}
.game-section-title{font-size:1.8rem;margin-bottom:20px;padding-left:10px;border-left:5px solid #333}
.game-section-title a{color:#333;text-decoration:none}
.game-section-title a:hover{color:#007bff}
.game-section-layout{display:flex!important;gap:20px;align-items:flex-start}
.game-icon-section{flex:0 0 240px!important;width:240px!important;display:block;position:relative;transition:all .3s;border-radius:12px;overflow:hidden;box-shadow:0 8px 20px rgba(0,0,0,.2)}
.game-icon-section:hover{transform:translateY(-8px) scale(1.02);box-shadow:0 12px 30px rgba(0,0,0,.3)}
.game-icon-image{width:100%!important;height:auto!important;display:block!important;border-radius:12px!important}
.game-products-section{flex:1!important;min-width:0!important;overflow:visible!important;position:relative}
.game-products-slider{position:relative;width:100%;padding:0 30px}
.game-products-slider .slick-list{overflow:hidden!important}
.game-products-slider .slick-track{display:flex!important}
.game-products-slider .slick-slide{height:auto!important;float:none!important;margin:0 10px}
.game-products-slider .slick-prev,.game-products-slider .slick-next{width:50px!important;height:50px!important;background:rgba(0,0,0,.7)!important;border-radius:50%!important;z-index:10!important;border:2px solid white!important;box-shadow:0 2px 8px rgba(0,0,0,.3)!important;top:50%!important;transform:translateY(-50%)!important;position:absolute!important}
.game-products-slider .slick-prev:hover,.game-products-slider .slick-next:hover{background:rgba(0,0,0,.9)!important}
.game-products-slider .slick-prev{left:0!important}
.game-products-slider .slick-next{right:0!important}
.game-products-slider .slick-prev:before,.game-products-slider .slick-next:before{content:""!important}
.game-products-slider .slick-disabled{opacity:.3!important}
.no-products{text-align:center;padding:60px 20px;color:#999}
@media(max-width:768px){
.game-section-layout{gap:15px}
.game-icon-section{flex:0 0 120px!important;width:120px!important}
.game-products-slider .slick-prev,.game-products-slider .slick-next{display:none!important}
.game-products-slider{padding:0}
.game-section-title{font-size:1.4rem}
}
@media(max-width:480px){
.game-icon-section{flex:0 0 100px!important;width:100px!important}
}
</style>', false);
// JS
$event->addSnippet('<script>
(function(){
if(typeof eccube==="undefined"||!eccube.productsClassCategories) return;
var gameCategories = ' . $gameCategoriesJson . ';
var $shelfGrid = $(".ec-shelfGrid");
var $items = $shelfGrid.find(".ec-shelfGrid__item");
if($items.length === 0) return;
var productsByCategory = {};
$items.each(function(){
var $item = $(this);
var categoryIds = $item.attr("data-category-ids");
if(!categoryIds) return;
var categories = categoryIds.split(",").map(function(id){ return parseInt(id.trim()); });
gameCategories.forEach(function(game){
if(categories.indexOf(game.id) !== -1){
if(!productsByCategory[game.id]) productsByCategory[game.id] = [];
productsByCategory[game.id].push($item.clone());
}
});
});
var $newLayout = $("<div class=\"game-category-parent-layout\"></div>");
gameCategories.forEach(function(game){
var products = productsByCategory[game.id] || [];
var $section = $("<div class=\"game-section\"></div>");
var $title = $("<h2 class=\"game-section-title\"><a href=\"?category_id=" + game.id + "\">" + game.name + "</a></h2>");
var $layout = $("<div class=\"game-section-layout\"></div>");
var iconHtml = game.icon ? "<img src=\"" + game.icon + "\" alt=\"" + game.name + "\" class=\"game-icon-image\">" : "<div style=\"width:100%;height:200px;background:#ccc;display:flex;align-items:center;justify-content:center;\">" + game.name + "</div>";
var $iconSection = $("<a href=\"?category_id=" + game.id + "\" class=\"game-icon-section\">" + iconHtml + "</a>");
var $productsSection = $("<div class=\"game-products-section\"></div>");
var $slider = $("<div class=\"game-products-slider slider-" + game.id + "\"></div>");
if(products.length > 0){
products.forEach(function($product){ $slider.append($product); });
} else {
$slider.html("<div class=\"no-products\"><p>商品準備中です</p></div>");
}
$productsSection.append($slider);
$layout.append($iconSection);
$layout.append($productsSection);
$section.append($title);
$section.append($layout);
$newLayout.append($section);
});
$shelfGrid.replaceWith($newLayout);
// Slick初期化
setTimeout(function(){
gameCategories.forEach(function(game){
var $slider = $(".slider-" + game.id);
if($slider.find(".ec-shelfGrid__item").length > 0 && typeof $.fn.slick !== "undefined"){
$slider.slick({
slidesToShow: 4,
slidesToScroll: 1,
infinite: false,
arrows: true,
prevArrow: "<button type=\"button\" class=\"slick-prev\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"white\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg></button>",
nextArrow: "<button type=\"button\" class=\"slick-next\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"white\"><path d=\"M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z\"/></svg></button>",
responsive: [
{breakpoint: 1200, settings: {slidesToShow: 3}},
{breakpoint: 768, settings: {slidesToShow: 1, arrows: false}},
{breakpoint: 480, settings: {slidesToShow: 1, arrows: false}}
]
});
}
});
}, 300);
})();
</script>', false);
} catch (\Exception $e) {
error_log('NZCategoryLayoutManager42: ' . $e->getMessage());
}
}
}