概要
仕事で論理削除を実装する必要が出てきたので調べたついでに残しておく
環境
- PHP → 7.1.23
- symfony/symfony → v3.4.18
- doctrine/orm → v2.6.2
- gedmo/doctrine-extensions → v2.4.36
- stof/doctrine-extensions-bundle → v1.3.0
設定
Doctrine拡張のインストール
$ composer require stof/doctrine-extensions-bundle
バンドルの有効化
app/AppKernel.php
<?php
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = [
// ...
new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
// ...
];
{
}
Configに設定
app/config/config.yml
doctrine:
orm:
# フィルターを利用したい場合はこれも書く
filters:
softdeleteable:
class: 'Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter'
enabled: true
# 論理削除設定
stof_doctrine_extensions:
default_locale: '%locale%'
orm:
default:
softdeleteable: true
Entityの準備
src/AppBundle/Entity/Product.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* Class Product
* @package AppBundle\Entity
* @ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository")
* @ORM\Table(name="product")
* @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false, hardDelete=true)
*/
class Product
{
/**
* @var int
*
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @var \DateTime
*
* @ORM\Column(type="datetime", nullable=true)
*/
private $deletedAt;
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @return \DateTime
*/
public function getDeletedAt()
{
return $this->deletedAt;
}
/**
* @param \DateTime $deletedAt
*/
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
}
}
DBに反映
$ bin/console doctrine:schema:update --force
使用例(フィルターと論理削除)
src/AppBundle/Controller/Admin/ProductController.php
<?php
/**
* Class ProductController
* @package AppBundle\Controller\Admin
* @Route("/admin/product")
*/
class ProductController extends Controller
{
/**
* 製品一覧(フィルター適用例)
* @Route("/", name="admin_product_list")
* @Method("GET")
*
* @param Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function listAction(Request $request)
{
// 製品一覧取得
/** @var EntityManager $em */
$em = $this->getDoctrine()->getManager();
// 論理削除したデータも含めて取得したい場合はフィルターを適用する(soft-deleteableは古い記述の仕方っぽい)
$em->getFilters()->disable('softdeleteable');
$products = $em->getRepository(Product::class)->findAll();
dump($products)
// ...
}
// ...
/**
* 製品削除(論理削除例)
*
* @Route("/{id}/delete", name="admin_product_delete")
* @Method("DELETE")
* @param Request $request
* @param Product $product
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function deleteAction(Request $request, Product $product)
{
// ...
// Entityで指定さえしておけば特別な記述なく論理削除できる
$em = $this->getDoctrine()->getManager();
$em->remove($product);
$em->flush();
// 現バージョンは2回削除を実行する事で物理削除となる(バグ?)
// $em->remove($product);
// $em->flush();
// 正常動作はこちらのはず
// $em->getFilters()->disable('softdeleteable');
// $em->remove($product);
// $em->flush();
// ...
}
}
注意点
- 論理削除したデータを取得しないのはORMを利用する場合だけなのでDQLとクエリビルダの時はwhereで指定する