<?php
namespace Plugin\ApgRichCategory;
use Doctrine\ORM\EntityManagerInterface;
use Eccube\Common\Constant;
use Eccube\Entity\Category;
use Eccube\Entity\Layout;
use Eccube\Entity\Master\DeviceType;
use Eccube\Entity\Page;
use Eccube\Entity\PageLayout;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Eccube\Event\TemplateEvent;
use Eccube\Repository\CategoryRepository;
use Eccube\Repository\LayoutRepository;
use Eccube\Repository\PageRepository;
use Eccube\Repository\ProductCategoryRepository;
use Eccube\Util\CacheUtil;
use Plugin\ApgRichCategory\Domain\InsertContentType;
use Plugin\ApgRichCategory\Domain\UrlType;
use Plugin\ApgRichCategory\Entity\Config;
use Plugin\ApgRichCategory\Repository\ConfigRepository;
use Plugin\ApgRichCategory\Util\Paths;
use SunCat\MobileDetectBundle\DeviceDetector\MobileDetector;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Router;
use Symfony\Component\Routing\RouterInterface;
class Event implements EventSubscriberInterface
{
const TEMPLATE_NAMESPACE = '@ApgRichCategory';
/** @var ConfigRepository */
protected $Config;
/** @var ProductCategoryRepository */
protected $ProductCategory;
/** @var EntityManagerInterface */
protected $em;
/** @var \Twig_Environment */
protected $twig;
/** @var Paths */
protected $path;
/** @var Router */
protected $router;
/** @var MobileDetector */
protected $mobileDetector;
/** @var CacheUtil */
protected $cacheUtil;
public function __construct(
ConfigRepository $configRepository,
ProductCategoryRepository $productCategoryRepository,
EntityManagerInterface $em,
\Twig_Environment $twig,
Paths $path,
RouterInterface $router,
CacheUtil $cacheUtil,
MobileDetector $mobileDetector
)
{
$this->Config = $configRepository;
$this->ProductCategory = $productCategoryRepository;
$this->em = $em;
$this->twig = $twig;
$this->path = $path;
$this->cacheUtil = $cacheUtil;
$this->router = $router;
$this->mobileDetector = $mobileDetector;
}
/**
* @return array
*/
public static function getSubscribedEvents()
{
return [
'@admin/Product/category.twig' => 'onAdminProductCategoryRender',
EccubeEvents::ADMIN_PRODUCT_CATEGORY_INDEX_COMPLETE => 'onAdminProductCategoryIndexComplete',
EccubeEvents::ADMIN_PRODUCT_CATEGORY_DELETE_COMPLETE => 'onAdminProductCategoryDeleteComplete',
EccubeEvents::FRONT_PRODUCT_INDEX_INITIALIZE => 'onFrontProductIndexInitialize',
'Product/list.twig' => 'onFrontProductListRender',
// 'kernel.request' => 'onKernelRequest', // @TODO
];
}
/**
* @param TemplateEvent $event
* @throws \Twig_Error_Loader
*/
public function onAdminProductCategoryRender(TemplateEvent $event)
{
$source = $event->getSource();
$parameters = $event->getParameters();
$pattern = '|<form class="form-row d-none mode-edit"(.*?)</form>|s';
if (Constant::VERSION <= '4.0.2') {
$addRow = $this->twig->getLoader()->getSourceContext(self::TEMPLATE_NAMESPACE . '/admin/product_category_edit.twig')->getCode();
if (preg_match($pattern, $source, $matches, PREG_OFFSET_CAPTURE)) {
$replacement = '<form class="form-row d-none mode-edit" enctype="multipart/form-data"' . $matches[1][0] . $addRow . '</form>';
$source = preg_replace($pattern, $replacement, $source);
}
} else {
$addRow = $this->twig->getLoader()->getSourceContext(self::TEMPLATE_NAMESPACE . '/admin/product_category_edit_over_4_0_3.twig')->getCode();
if (preg_match($pattern, $source, $matches, PREG_OFFSET_CAPTURE)) {
$replacement = '<form class="form-row d-none mode-edit" enctype="multipart/form-data"' . $matches[1][0] . $addRow . '</form>';
$source = preg_replace($pattern, $replacement, $source);
}
}
$event->setSource($source);
$event->setParameters($parameters);
$event->addSnippet(self::TEMPLATE_NAMESPACE . '/admin/upload_file_js.twig');
}
/**
* @param Event $event
*/
public function onAdminProductCategoryIndexComplete(EventArgs $event)
{
/** @var FormInterface $form */
$form = $event->getArgument('form');
/** @var Category $Category */
$Category = $event->getArgument('TargetCategory');
$imageFile = null;
$fileDeleteFlag = false;
$slug = $Category->getSlug();
if (!empty($slug)) {
$slug = ltrim($slug, "/");
}
$Category->setSlug($slug);
// キャッシュを削除する
$this->cacheUtil->clearCache();
// @FIXME EC-CUBEコアのバグで、正しくform情報を渡してくれないので$_FILEから取得する
if (isset($_FILES['admin_category'])) {
/** @var UploadedFile $imageFile */
$imageFile = $form->get('upload_file')->getData();
} elseif (!empty($_FILES)) {
$values = array_values($_FILES);
$v = $values[0];
$prop = 'upload_file';
$imageFile = new UploadedFile($v['tmp_name'][$prop], $v['name'][$prop], $v['type'][$prop], $v['size'][$prop], $v['error'][$prop]);
$fileDeleteFlag = !empty($Category->getFileDeleteFlag());
}
$orgImageFileName = $Category->getFileName();
if (empty($fileDeleteFlag) && !empty($imageFile) && $imageFile->getSize() > 0) {
$extension = $imageFile->getClientOriginalExtension();
$fileName = date('mdHis') . uniqid('_') . '.' . $extension;
} elseif (!empty($fileDeleteFlag)) {
$fileName = null;
} else {
$fileName = $orgImageFileName;
}
$baseFilePath = $this->path->getBasePath();
$filePath = $this->path->categoryImagesRealPath();
if (empty($fileDeleteFlag)) {
if (!empty($imageFile) && $imageFile->getSize() > 0) {
$imageFile->move($baseFilePath . $filePath, $fileName);
}
} elseif (!empty($orgImageFileName)) {
@unlink($baseFilePath . $filePath . $orgImageFileName);
}
$Category->setFileName($fileName);
$this->ProductCategory->save($Category);
$this->em->flush($Category);
}
public function onAdminProductCategoryDeleteComplete(EventArgs $event)
{
/** @var Category $Category */
$Category = $event->getArgument('TargetCategory');
if (!empty($Category->getFileName())) {
$baseFilePath = $this->path->getBasePath();
$filePath = $this->path->categoryImagesRealPath();
$fileSystem = new Filesystem();
$fileSystem->remove($baseFilePath . $filePath . $Category->getFileName());
}
}
public function onFrontProductIndexInitialize(EventArgs $event)
{
/** @var Request $request */
$request = $event->getRequest();
/** @var ConfigRepository $configRepository */
$configRepository = $this->em->getRepository(Config::class);
$config = $configRepository->getOrNew();
if ($config->getUrlType() === UrlType::SLUG) {
/** @var CategoryRepository $categoryRepository */
$categoryRepository = $this->em->getRepository(Category::class);
$pathInfo = $request->getPathInfo();
$path = ltrim($pathInfo, "/");
/** @var Category $Category */
$Category = $categoryRepository->findOneBy([
'slug' => $path
]);
if (!empty($Category)) {
$request->query->add(['category_id' => $Category->getId()]);
$this->setPageLayout();
}
} elseif ($config->getUrlType() === UrlType::ID) {
$categoryId = $request->attributes->get('category_id');
if (!empty($categoryId)) {
$request->query->add(['category_id' => $categoryId]);
$this->setPageLayout();
}
}
}
protected function setPageLayout()
{
// PageLayout の設定
$route = 'product_list';
$type = DeviceType::DEVICE_TYPE_PC;
if ($this->mobileDetector->isMobile()) {
$type = DeviceType::DEVICE_TYPE_MB;
}
// URLからPageを取得
/** @var PageRepository $pageRepository */
$pageRepository = $this->em->getRepository(Page::class);
$Page = $pageRepository->getPageByRoute($route);
if (!empty($Page)) {
/** @var PageLayout[] $PageLayouts */
$PageLayouts = $Page->getPageLayouts();
// Pageに紐づくLayoutからDeviceTypeが一致するLayoutを探す
$Layout = null;
foreach ($PageLayouts as $PageLayout) {
if ($PageLayout->getDeviceTypeId() == $type) {
$Layout = $PageLayout->getLayout();
break;
}
}
// Pageに紐づくLayoutにDeviceTypeが一致するLayoutがない場合はPCのレイアウトを探す
if (!$Layout) {
log_info('fallback to PC layout');
foreach ($PageLayouts as $PageLayout) {
if ($PageLayout->getDeviceTypeId() == DeviceType::DEVICE_TYPE_PC) {
$Layout = $PageLayout->getLayout();
break;
}
}
}
if ($Layout) {
// lazy loadを制御するため, Layoutを取得しなおす.
/** @var LayoutRepository $layoutRepository */
$layoutRepository = $this->em->getRepository(Layout::class);
$Layout = $layoutRepository->get($Layout->getId());
$this->twig->addGlobal('Layout', $Layout);
}
$this->twig->addGlobal('Page', $Page);
$this->twig->addGlobal('title', $Page->getName());
}
}
/**
* @param TemplateEvent $event
* @throws \Twig_Error_Loader
*/
public function onFrontProductListRender(TemplateEvent $event)
{
$source = $event->getSource();
$parameters = $event->getParameters();
if (!empty($parameters['Category'])) {
/** @var Category $Category */
$Category = $parameters['Category'];
/** @var Config $config */
$config = $this->Config->getOrNew();
if (!empty($Category->getMetaDescription())) {
/** @var \Twig_Environment $twig */
$globals = $this->twig->mergeGlobals(array());
if (isset($globals['Page'])) {
/** @var Page $page */
$page = $globals['Page'];
$page->setDescription($Category->getMetaDescription());
}
}
// data
$insertContentType = $config->getInsertContentType();
if ($insertContentType === InsertContentType::UPPER) {
$pattern = '|<div class="ec-searchnavRole__topicpath">|';
$addRow = $this->twig->getLoader()->getSourceContext('ApgRichCategory/Resource/template/front/insert_content.twig')->getCode();
if (preg_match($pattern, $source, $matches, PREG_OFFSET_CAPTURE)) {
$replacement = $addRow . $matches[0][0];
$source = preg_replace($pattern, $replacement, $source);
}
} elseif ($insertContentType === InsertContentType::BOTTOM) {
$pattern = '{% block main %}';
$pattern2 = '|{% endblock %}|';
$addRow = $this->twig->getLoader()->getSourceContext('ApgRichCategory/Resource/template/front/insert_content.twig')->getCode();
if ($pos = strpos($source, $pattern)) {
$splitContent = substr($source, $pos);
if (preg_match($pattern2, $splitContent, $matches, PREG_OFFSET_CAPTURE)) {
$replacement = $addRow . $matches[0][0];
$replaceContent = preg_replace($pattern2, $replacement, $splitContent);
$source = str_replace($splitContent, $replaceContent, $source);
}
}
}
}
$event->setParameters($parameters);
$event->setSource($source);
$event->addAsset(self::TEMPLATE_NAMESPACE . '/front/render_product_list_css.twig');
}
}