EC-CUBE4で商品に販売期間を設定する方法です。
販売期間を設定していて販売期間内の商品のみ商品一覧と商品詳細ページに表示させるようにします。
dtb_productテーブルに販売開始日時と販売終了日時カラムを追加
dtb_productテーブルに販売開始日時と販売終了日時カラムを追加します。
サンプルコードは以下のとおりです。
<?php
namespace Customize\Entity;
use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation\EntityExtension;
/**
* dtb_productテーブルに販売開始日時と販売位終了日時カラム追加
*
* @EntityExtension("Eccube\Entity\Product")
*/
trait ProductTrait
{
/**
* @ORM\Column(type="datetimetz", nullable=true)
*/
private $sale_start;
/**
* @ORM\Column(type="datetimetz", nullable=true)
*/
private $sale_end;
public function getSaleStart(): ?\DateTimeInterface
{
return $this->sale_start;
}
public function setSaleStart(?\DateTimeInterface $sale_start): self
{
$this->sale_start = $sale_start;
return $this;
}
public function getSaleEnd(): ?\DateTimeInterface
{
return $this->sale_end;
}
public function setSaleEnd(?\DateTimeInterface $sale_end): self
{
$this->sale_end = $sale_end;
return $this;
}
}
ProductTraitを作ったら以下のコマンドを実行してください。
bin/console eccube:generate:proxies bin/console doctrine:schema:update --force
商品登録フォームに販売開始日時と販売位終了日時項目を追加
商品登録フォームに販売開始日時と販売位終了日時項目を追加します。
サンプルコードは以下のとおりです。
<?php
namespace Customize\Form\Extension;
use Eccube\Form\Type\Admin\ProductType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
/**
* 商品登録フォームに販売開始日時と販売位終了日時項目を追加
*
* Class ProductTypeExtension
* @package Customize\Form\Extension
*/
class ProductTypeExtension extends AbstractTypeExtension
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('sale_start', DateTimeType::class, [
'label' => '販売開始日時',
'required' => false,
'years' => range(date('Y'), date('Y') + 10),
'placeholder' => [
'year' => '----', 'month' => '--', 'day' => '--', 'hour' => '--', 'minute' => '--'
],
'eccube_form_options' => [
'auto_render' => true
]
])
->add('sale_end', DateTimeType::class, [
'label' => '販売終了日時',
'required' => false,
'years' => range(date('Y'), date('Y') + 10),
'placeholder' => [
'year' => '----', 'month' => '--', 'day' => '--', 'hour' => '--', 'minute' => '--'
],
'eccube_form_options' => [
'auto_render' => true
]
])
;
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$form = $event->getForm();
$start = $form['sale_start']->getData();
$end = $form['sale_end']->getData();
// 販売開始日時が販売終了日時より大きいときエラー
if ($start && $end && ($end < $start)) {
$form['sale_start']->addError(new FormError("販売開始日時がおかしいです。"));
}
// 販売開始日時が空で販売終了日時が空じゃないときエラー
if(empty($start) && $end) {
$form['sale_start']->addError(new FormError("販売開始日時を設定してください。"));
}
// 販売終了日時が空で販売開始日時が空じゃないときエラー
if($start && empty($end)) {
$form['sale_end']->addError(new FormError("販売終了日時を設定してください。"));
}
});
}
/**
* {@inheritdoc}
*/
public function getExtendedType()
{
return ProductType::class;
}
}
こんな感じで表示されます。
販売期間外の商品は商品一覧から非表示設定
販売期間外の商品は商品一覧から非表示にするよう設定します。
販売期間を設定していない商品も非表示にしているので、販売期間設定をしていない商品は表示させたい場合は絞り込み条件を調整してください。
サンプルコードは以下のとおりです。
<?php
namespace Customize\Repository\QueryCustomizer;
use Doctrine\ORM\QueryBuilder;
use Eccube\Doctrine\Query\QueryCustomizer;
use Eccube\Repository\QueryKey;
/**
* 販売期間外の商品は商品一覧から非表示
*
* Class NowOnSaleCustomizer
* @package Customize\Repository\QueryCustomizer
*/
class NowOnSaleCustomizer implements QueryCustomizer
{
/**
* @inheritDoc
*/
public function customize(QueryBuilder $builder, $params, $queryKey)
{
// これは商品詳細ページで利用します
if(isset($params["id"]) && !empty($params["id"])) {
$builder
->andWhere("p.id = :id")
->setParameter("id", $params["id"]);
}
// 販売期間中の商品のみに絞り込み
$builder
->andWhere("p.sale_start <= :now")
->andWhere("p.sale_end >= :now")
->setParameter("now", new \DateTime());
}
/**
* @inheritDoc
*/
public function getQueryKey()
{
return QueryKey::PRODUCT_SEARCH;
}
}
販売期間外の商品はNot Foundにする
販売期間外の商品は商品詳細ページをNot Foundにします。
サンプルコードは以下のとおりです。
<?php
namespace Customize\EventSubscriber;
use Eccube\Event\EventArgs;
use Eccube\Repository\ProductRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* 商品が販売期間中かチェック
*
* Class NowOnSaleSubscriber
* @package Customize\EventSubscriber
*/
class NowOnSaleSubscriber implements EventSubscriberInterface
{
/**
* @var ProductRepository
*/
private $productRepository;
public function __construct(
ProductRepository $productRepository
) {
$this->productRepository = $productRepository;
}
public function onFrontProductDetailInitialize(EventArgs $event)
{
$Product = $event->getArgument("Product");
// 販売期間中商品かチェック
$qb = $this->productRepository->getQueryBuilderBySearchData([
"id" => $Product->getId()
]);
$result = $qb->getQuery()->getResult();
// 販売期間中じゃなければNot Fount
if(!$result) {
throw new NotFoundHttpException();
}
}
public static function getSubscribedEvents()
{
return [
'front.product.detail.initialize' => 'onFrontProductDetailInitialize',
];
}
}
以上で完成です。


eccube4.2にて試してみましたがNowOnSaleSubscriber.phpのthrow new NotFoundHttpException();の部分で
HTTP 404 Not Foundエラーが出ます。
販売期間中ではないからHTTP 404 Not Foundエラーが発生してるのではないでしょうか?