本文目录导读:

我来详细介绍 Symfony Form 和永久删除功能的实现。
Symfony Form 基础
创建表单类型
// src/Form/ProductType.php
namespace App\Form;
use App\Entity\Product;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class, [
'label' => '产品名称',
'attr' => ['class' => 'form-control']
])
->add('price', NumberType::class, [
'label' => '价格',
'attr' => ['class' => 'form-control']
])
->add('description', TextareaType::class, [
'label' => '描述',
'required' => false,
'attr' => ['class' => 'form-control', 'rows' => 5]
])
->add('submit', SubmitType::class, [
'label' => '保存',
'attr' => ['class' => 'btn btn-primary']
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Product::class,
]);
}
}
在控制器中使用表单
// src/Controller/ProductController.php
namespace App\Controller;
use App\Entity\Product;
use App\Form\ProductType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class ProductController extends AbstractController
{
#[Route('/product/new', name: 'product_new')]
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$product = new Product();
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($product);
$entityManager->flush();
$this->addFlash('success', '产品创建成功!');
return $this->redirectToRoute('product_list');
}
return $this->render('product/new.html.twig', [
'form' => $form->createView()
]);
}
#[Route('/product/edit/{id}', name: 'product_edit')]
public function edit(Request $request, Product $product, EntityManagerInterface $entityManager): Response
{
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->flush();
$this->addFlash('success', '产品更新成功!');
return $this->redirectToRoute('product_list');
}
return $this->render('product/edit.html.twig', [
'form' => $form->createView(),
'product' => $product
]);
}
}
永久删除功能实现
实体配置(软删除 vs 硬删除)
// src/Entity/Product.php
namespace App\Entity;
use App\Repository\ProductRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: ProductRepository::class)]
class Product
{
// ... 其他字段
// 软删除字段
#[ORM\Column(type: 'datetime', nullable: true)]
private ?\DateTimeInterface $deletedAt = null;
// Getter 和 Setter
public function getDeletedAt(): ?\DateTimeInterface
{
return $this->deletedAt;
}
public function setDeletedAt(?\DateTimeInterface $deletedAt): self
{
$this->deletedAt = $deletedAt;
return $this;
}
// 检查是否已删除
public function isDeleted(): bool
{
return $this->deletedAt !== null;
}
// 执行软删除
public function softDelete(): self
{
$this->deletedAt = new \DateTime();
return $this;
}
// 恢复软删除
public function restore(): self
{
$this->deletedAt = null;
return $this;
}
}
软删除仓库方法
// src/Repository/ProductRepository.php
namespace App\Repository;
use App\Entity\Product;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class ProductRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Product::class);
}
// 查询未删除的产品
public function findActive(): array
{
return $this->createQueryBuilder('p')
->where('p.deletedAt IS NULL')
->orderBy('p.id', 'DESC')
->getQuery()
->getResult();
}
// 查询已删除的产品(回收站)
public function findDeleted(): array
{
return $this->createQueryBuilder('p')
->where('p.deletedAt IS NOT NULL')
->orderBy('p.deletedAt', 'DESC')
->getQuery()
->getResult();
}
// 永久删除过期的软删除记录
public function permanentDeleteOldRecords(int $days = 30): int
{
$date = new \DateTime("-{$days} days");
return $this->createQueryBuilder('p')
->delete()
->where('p.deletedAt IS NOT NULL')
->andWhere('p.deletedAt < :date')
->setParameter('date', $date)
->getQuery()
->execute();
}
}
删除控制器方法
// src/Controller/ProductController.php(续)
class ProductController extends AbstractController
{
// 软删除
#[Route('/product/soft-delete/{id}', name: 'product_soft_delete', methods: ['POST'])]
public function softDelete(Request $request, Product $product, EntityManagerInterface $entityManager): Response
{
// CSRF 保护
if ($this->isCsrfTokenValid('delete'.$product->getId(), $request->request->get('_token'))) {
$product->softDelete();
$entityManager->flush();
$this->addFlash('success', '产品已移至回收站');
}
return $this->redirectToRoute('product_list');
}
// 永久删除
#[Route('/product/permanent-delete/{id}', name: 'product_permanent_delete', methods: ['POST'])]
public function permanentDelete(Request $request, Product $product, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('permanent_delete'.$product->getId(), $request->request->get('_token'))) {
$entityManager->remove($product);
$entityManager->flush();
$this->addFlash('success', '产品已永久删除');
}
return $this->redirectToRoute('product_list');
}
// 恢复软删除
#[Route('/product/restore/{id}', name: 'product_restore', methods: ['POST'])]
public function restore(Request $request, Product $product, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('restore'.$product->getId(), $request->request->get('_token'))) {
$product->restore();
$entityManager->flush();
$this->addFlash('success', '产品已恢复');
}
return $this->redirectToRoute('product_trash');
}
// 清空回收站
#[Route('/product/empty-trash', name: 'product_empty_trash', methods: ['POST'])]
public function emptyTrash(ProductRepository $productRepository, EntityManagerInterface $entityManager): Response
{
$deletedProducts = $productRepository->findDeleted();
foreach ($deletedProducts as $product) {
$entityManager->remove($product);
}
$entityManager->flush();
$this->addFlash('success', '回收站已清空');
return $this->redirectToRoute('product_list');
}
}
Twig 模板示例
{# templates/product/list.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<div class="container mt-4">
<h1>产品列表</h1>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>价格</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for product in products %}
<tr>
<td>{{ product.id }}</td>
<td>{{ product.name }}</td>
<td>{{ product.price }}</td>
<td>
<a href="{{ path('product_edit', {'id': product.id}) }}" class="btn btn-sm btn-warning">编辑</a>
{# 软删除按钮 #}
<form method="post" action="{{ path('product_soft_delete', {'id': product.id}) }}" style="display: inline-block;" onsubmit="return confirm('确定要删除此产品吗?');">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ product.id) }}">
<button class="btn btn-sm btn-danger">删除</button>
</form>
{# 永久删除按钮 #}
<form method="post" action="{{ path('product_permanent_delete', {'id': product.id}) }}" style="display: inline-block;" onsubmit="return confirm('确定要永久删除此产品吗?此操作不可恢复!');">
<input type="hidden" name="_token" value="{{ csrf_token('permanent_delete' ~ product.id) }}">
<button class="btn btn-sm btn-dark">永久删除</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
批量操作(回收站)
// src/Controller/ProductController.php(续)
#[Route('/product/trash', name: 'product_trash')]
public function trash(ProductRepository $productRepository): Response
{
$deletedProducts = $productRepository->findDeleted();
return $this->render('product/trash.html.twig', [
'products' => $deletedProducts
]);
}
#[Route('/product/batch-delete', name: 'product_batch_delete', methods: ['POST'])]
public function batchDelete(Request $request, EntityManagerInterface $entityManager): Response
{
$productIds = $request->request->get('product_ids', []);
if (!empty($productIds)) {
$products = $entityManager->getRepository(Product::class)->findBy(['id' => $productIds]);
foreach ($products as $product) {
$entityManager->remove($product);
}
$entityManager->flush();
$this->addFlash('success', '批量删除成功');
}
return $this->redirectToRoute('product_list');
}
安全考虑
// 添加 Voter 进行权限控制
// src/Security/ProductVoter.php
namespace App\Security;
use App\Entity\Product;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class ProductVoter extends Voter
{
const DELETE = 'delete';
const PERMANENT_DELETE = 'permanent_delete';
protected function supports(string $attribute, $subject): bool
{
if (!in_array($attribute, [self::DELETE, self::PERMANENT_DELETE])) {
return false;
}
if (!$subject instanceof Product) {
return false;
}
return true;
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
/** @var Product $product */
$product = $subject;
return match($attribute) {
self::DELETE => $this->canDelete($product, $user),
self::PERMANENT_DELETE => $this->canPermanentDelete($product, $user),
default => false,
};
}
private function canDelete(Product $product, User $user): bool
{
// 只有管理员或创建者可以删除
return $user === $product->getCreatedBy() || in_array('ROLE_ADMIN', $user->getRoles());
}
private function canPermanentDelete(Product $product, User $user): bool
{
// 只有管理员可以永久删除
return in_array('ROLE_ADMIN', $user->getRoles());
}
}
这样实现后,你就拥有了完整的表单处理和删除功能,包括软删除、永久删除、恢复和批量操作,以及权限控制。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播