<?php
/*
* This file is part of PrivateURL42
*
* Copyright(c) Akira Kurozumi <info@a-zumi.net>
*
* https://a-zumi.net
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Plugin\PrivateURL42\Doctrine\EventSubscriber;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Events;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Eccube\Entity\Master\ProductStatus;
use Eccube\Entity\Product;
use Eccube\Request\Context;
use Eccube\Util\StringUtil;
use Plugin\PrivateURL42\Common\Constant;
use Symfony\Component\HttpFoundation\RequestStack;
class PrivateSubscriber implements EventSubscriber
{
/**
* @var Context
*/
protected Context $requestContext;
/**
* @var EntityManagerInterface
*/
protected EntityManagerInterface $entityManager;
/**
* @var RequestStack
*/
private RequestStack $requestStack;
public function __construct(
Context $requestContext,
EntityManagerInterface $entityManager,
RequestStack $requestStack
) {
$this->requestContext = $requestContext;
$this->entityManager = $entityManager;
$this->requestStack = $requestStack;
}
/**
* @return array|string[]
*/
public function getSubscribedEvents(): array
{
return [
Events::postLoad,
Events::preUpdate,
Events::prePersist,
];
}
/**
* Product読み込み時の処理
*
* @param LifecycleEventArgs $args
*
* @return void
*/
public function postLoad(LifecycleEventArgs $args): void
{
$entity = $args->getObject();
$entityManager = $args->getObjectManager();
if ($entity instanceof Product) {
// フロント処理
if ($this->requestContext->isFront()) {
$private_key = $this->requestStack->getSession()->get(Constant::SESSION_PLG_PRIVATE_URL_PRIVATE_KEY.'_'.$entity->getId());
// セッションに保持されているプライベートキーがDBと一致したら、商品ステータスを一時的に公開に変更
if ($private_key && $entity->getPlgPuPrivateKey() === $private_key) {
$productStatus = $entityManager->find(ProductStatus::class, ProductStatus::DISPLAY_SHOW);
$entity->setStatus($productStatus);
}
}
}
}
/**
* Product更新前処理
*
* @param PreUpdateEventArgs $args
*
* @return void
*/
public function preUpdate(PreUpdateEventArgs $args): void
{
$entity = $args->getObject();
if ($entity instanceof Product) {
// 管理画面処理
if ($this->requestContext->isAdmin()) {
// 限定公開URL生成に変化があった場合
if ($args->hasChangedField('plg_pu_private')) {
// 有効化された場合プライベートキー発行
if ($entity->isPlgPuPrivate()) {
$key = $this->getUniquePrivateKey();
$entity->setPlgPuPrivateKey($key);
} else {
// 無効化されたらプライベートキー削除
$entity->setPlgPuPrivateKey(null);
// セッションから削除
$this->requestStack->getSession()->remove(Constant::SESSION_PLG_PRIVATE_URL_PRIVATE_KEY.'_'.$entity->getId());
}
}
}
// フロント処理
if ($this->requestContext->isFront()) {
// postLoadで公開に変更した場合、商品ステータスを非公開に戻す
if ($args->hasChangedField('Status')) {
$entity->setStatus($args->getOldValue('Status'));
}
}
}
}
/**
* 新規作成したときに限定公開URL生成が有効だったら秘密キーを生成
*
* @param LifecycleEventArgs $args
*
* @return void
*/
public function prePersist(LifecycleEventArgs $args): void
{
$entity = $args->getObject();
if ($entity instanceof Product) {
// 管理画面処理
if ($this->requestContext->isAdmin()) {
// 有効化された場合プライベートキー発行
if ($entity->isPlgPuPrivate()) {
$key = $this->getUniquePrivateKey();
$entity->setPlgPuPrivateKey($key);
}
}
}
}
/**
* @return string
*/
private function getUniquePrivateKey(): string
{
do {
$key = StringUtil::random(32);
$Product = $this->entityManager->getRepository(Product::class)->findOneBy(['plg_pu_private_key' => $key]);
} while ($Product);
return $key;
}
}