【EC-CUBE4】商品の公開日時が指定できる予約投稿機能を実装する方法

EC-CUBE4で商品の公開日時が指定できる予約投稿機能を実装する方法です。

今回実装する機能は以下のとおりです。

  • 非公開商品に対して公開日時を設定
  • 非公開商品に設定されている公開日時を超えたら公開
  • 公開日時が設定されている場合、公開日時を過ぎている商品は非公開に設定しても公開に自動で設定されます
  • 非公開にしたい場合は、公開日時設定をクリアする必要があります

 

dtb_productデーブルに公開日時設定カラムを追加

dtb_productデーブルに公開日時設定カラムを追加します。

サンプルコードは以下のとおりです。

<?php

namespace Customize\Entity;

use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation\EntityExtension;

/**
 * @EntityExtension("Eccube\Entity\Product")
 */
trait ProductTrait
{
    /**
     * @ORM\Column(type="datetimetz", nullable=true)
     */
    private $publish_date;

    public function getPublishDate(): ?\DateTimeInterface
    {
        return $this->publish_date;
    }

    public function setPublishDate(?\DateTimeInterface $publish_date): self
    {
        $this->publish_date = $publish_date;

        return $this;
    }
}

 

商品登録フォームに公開日時設定項目を追加

商品登録フォームに公開日時設定項目を追加します。

サンプルコードは以下のとおりです。

<?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;

class ProductTypeExtension extends AbstractTypeExtension
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('publish_date', DateTimeType::class, [
            'label' => '公開予定日時',
            'required' => false,
            'years' => range(date('Y'), date('Y') + 10),
            'placeholder' => [ 'year' => '----', 'month' => '--', 'day' => '--', 'hour' => '--', 'minute' => '--' ],
            'eccube_form_options' => [
                'auto_render' => true
            ]
        ]);
    }

    /**
    * {@inheritdoc}
    */
    public function getExtendedType()
    {
        return ProductType::class;
    }
}

 

以下のように表示されます。

 

公開日時が過ぎている非公開商品を公開設定するイベント作成

公開日時が過ぎている非公開商品を公開設定するイベント作成します。

サンプルコードは以下のとおりです。

<?php

namespace Customize\EventSubscriber;

use Doctrine\ORM\EntityManagerInterface;
use Eccube\Entity\Master\ProductStatus;
use Eccube\Repository\Master\ProductStatusRepository;
use Eccube\Repository\ProductRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * サイトにアクセスしたとき、非公開で予定公開日時を過ぎている商品を公開にするイベント
 *
 * Class SchedulePostsSubscriber
 * @package Customize\EventSubscriber
 */
class SchedulePostsSubscriber implements EventSubscriberInterface
{
    /**
     * @var ProductRepository
     */
    private $productRepository;

    /**
     * @var ProductStatusRepository
     */
    private $productStatusRepository;

    /**
     * @var EntityManagerInterface
     */
    private $entityManager;

    public function __construct(
        ProductRepository $productRepository,
        ProductStatusRepository $productStatusRepository,
        EntityManagerInterface $entityManager
    )
    {
        $this->productRepository = $productRepository;
        $this->productStatusRepository = $productStatusRepository;
        $this->entityManager = $entityManager;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        // 非公開で予定公開日時を過ぎている商品を探す
        $qb = $this->productRepository->createQueryBuilder("p");
        $qb
            ->where("p.Status = :Status")
            ->andWhere("p.publish_date < :now")
            ->setParameters([
                "Status" => ProductStatus::DISPLAY_HIDE,
                "now" => new \DateTime()
            ]);

        $result = $qb->getQuery()->getResult();

        // 非公開で予定公開日時を過ぎている商品が見つかったら
        if($result) {
            // 商品ステータスの公開を取得
            $Status = $this->productStatusRepository->find(ProductStatus::DISPLAY_SHOW);
            foreach($result as $Product) {
                // 商品ステータスの公開をセット
                $Product->setStatus($Status);
                $this->entityManager->persist($Product);
            }
            $this->entityManager->flush();
        }
    }

    public static function getSubscribedEvents()
    {
        return [
            'kernel.request' => 'onKernelRequest',
        ];
    }
}

 

以上で完成です。

お気軽にコメントをどうぞ

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください