我正在开发一个包含文章和评论系统的博客,我希望当后端的人删除文章时,文章的评论也会被删除,因为表格评论与表格文章和表格用户有关
我只想删除文章及其评论。
我尝试了这段代码,但它不起作用,它给我一个这样的错误:
EntityManager #remove()要求参数1为实体对象,给定NULL。
我尝试使用getter和setter获取注释,但它不起作用并告诉我这个方法在控制器中不存在。
我的控制器:
// remove an article
/**
* @Route("admin/supprimer/{id}")
* @param int $id
* @return Response
*/
public function delete(int $id): Response
{
$comment = $this->getDoctrine()->getRepository(Comments::class)->find($id);
if ($comment === null) {
$comments = $this->getDoctrine()->getManager();
$comments->remove($comment);
$comments->flush();
}
$article = $this->getDoctrine()
->getRepository(Articles::class)
->find($id);
$manager = $this->getDoctrine()->getManager();
$manager->remove($article);
$manager->flush();
$this->addFlash('deleteArticle', 'L\'article a bien étais supprimer');
return $this->redirectToRoute('app_backoffice_admin');
}
评论实体:
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\CommentsRepository")
*/
class Comments
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="text", nullable=false)
*/
private $commentsContent;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="comments")
* @ORM\JoinColumn(nullable=false)
*/
private $userComments;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Articles", inversedBy="comments")
*/
private $articleComments;
public function __construct()
{
$this->userComments = new ArrayCollection();
$this->articleComments = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function getCommentsContent(): ?string
{
return $this->commentsContent;
}
public function setCommentsContent(?string $commentsContent): self
{
$this->commentsContent = $commentsContent;
return $this;
}
public function getUserComments(): ?User
{
return $this->userComments;
}
public function setUserComments(?User $userComments): self
{
$this->userComments = $userComments;
return $this;
}
public function getArticleComments(): ?Articles
{
return $this->articleComments;
}
public function setArticleComments(?Articles $articleComments): self
{
$this->articleComments = $articleComments;
return $this;
}
}
文章实体:
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* @ORM\Entity(repositoryClass="App\Repository\ArticlesRepository")
* @ORM\HasLifecycleCallbacks()
* @Vich\Uploadable
*/
class Articles
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Assert\Length(
* min = 5,
* max = 255,
* minMessage = "le contenu de titre doit avoir au minimum {{ limit }} carctère",
* maxMessage = "le contenu de titre ne doit dépasser {{ limit }} carctère"
* )
*/
private $nameArticle;
/**
* @ORM\Column(type="text", nullable=false)
* @Assert\Length(
* min = 50,
* minMessage = "le contenu de titre doit avoir au minimum {{ limit }} carctère",
* )
*/
private $articleContent;
/**
* @var \DateTime
* @Gedmo\Timestampable(on="create")
* @ORM\Column(name="created_at", type="datetime", nullable=false)
*/
private $createdAt;
/**
* @var \DateTime
* @Gedmo\Timestampable(on="update")
* @ORM\Column(name="updated_at", type="datetime", nullable=false)
*/
private $updatedAt;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="articles", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
*/
private $category;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* @Vich\UploadableField(mapping="articles_image", fileNameProperty="imageName", size="imageSize")
*
* @var File
*/
private $imageFile;
/**
* @ORM\Column(type="string", length=255)
*
* @var string
*/
private $imageName;
/**
* @ORM\Column(type="integer")
*
* @var integer
*/
private $imageSize;
/**
* @ORM\Column(type="text")
*/
private $introduction;
/**
* @Gedmo\Slug(fields={"nameArticle"},separator="-", updatable=true, unique=true)
* @ORM\Column(type="string", length=255)
*/
private $slug;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Comments", mappedBy="articleComments")
*/
private $comments;
public function __construct()
{
$this->createdAt = new \DateTime("now", new \DateTimeZone('Europe/Paris'));
$this->comments = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function getNameArticle(): ?string
{
return $this->nameArticle;
}
public function setNameArticle(string $nameArticle): self
{
$this->nameArticle = $nameArticle;
return $this;
}
public function getArticleContent(): ?string
{
return $this->articleContent;
}
public function setArticleContent(string $articleContent): self
{
$this->articleContent = $articleContent;
return $this;
}
/**
* Get createdAt
*
* @return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Get updatedAt
*
* @return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): self
{
$this->category = $category;
return $this;
}
/**
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
* @throws \Exception
*/
public function setImageFile(?File $image = null): void
{
$this->imageFile = $image;
if (null !== $image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTimeImmutable();
}
}
public function getImageFile(): ?File
{
return $this->imageFile;
}
public function setImageName(?string $imageName): void
{
$this->imageName = $imageName;
}
public function getImageName(): ?string
{
return $this->imageName;
}
public function setImageSize(?int $imageSize): void
{
$this->imageSize = $imageSize;
}
public function getImageSize(): ?int
{
return $this->imageSize;
}
public function getIntroduction(): ?string
{
return $this->introduction;
}
public function setIntroduction(string $introduction): self
{
$this->introduction = $introduction;
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
/**
* @return Collection|Comments[]
*/
public function getComments(): Collection
{
return $this->comments;
}
public function addComment(Comments $comment): self
{
if (!$this->comments->contains($comment)) {
$this->comments[] = $comment;
$comment->setArticleComments($this);
}
return $this;
}
public function removeComment(Comments $comment): self
{
if ($this->comments->contains($comment)) {
$this->comments->removeElement($comment);
// set the owning side to null (unless already changed)
if ($comment->getArticleComments() === $this) {
$comment->setArticleComments(null);
}
}
return $this;
}
}
用户实体:
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
* @ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @Assert\Regex("/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{6,}$/",
* message = "Votre mot de passe doit contenir minimum 6 carctère avec une miniscule majuscule un chiffre "
* )
*
* @var string
*/
//protected $password;
/**
* @Assert\Email(
* message = "l'adresse mail n'est pas valide"
* )
* @var string
*/
protected $email;
/**
* @ORM\Column(type="string", length=255)
* @var string
*/
protected $age;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Comments", mappedBy="userComments", orphanRemoval=true)
*/
private $comments;
public function __construct()
{
parent::__construct();
$this->comments = new ArrayCollection();
}
public function getAge(): ?string
{
return $this->age;
}
public function setAge(string $age): self
{
$this->age = $age;
return $this;
}
/**
* Place un rôle unique à l'utilisateur (supprimer tous les anciens rôles)
* @param string $userRole
*/
public function setRole(string $userRole)
{
// Vider les rôles
foreach ($this->getRoles() as $role) {
$this->removeRole($role);
}
// Ajout le rôle unique passé en paramètre
$this->addRole($userRole);
}
/**
* @return Collection|Comments[]
*/
public function getComments(): Collection
{
return $this->comments;
}
public function addComment(Comments $comment): self
{
if (!$this->comments->contains($comment)) {
$this->comments[] = $comment;
$comment->setUserComments($this);
}
return $this;
}
public function removeComment(Comments $comment): self
{
if ($this->comments->contains($comment)) {
$this->comments->removeElement($comment);
// set the owning side to null (unless already changed)
if ($comment->getUserComments() === $this) {
$comment->setUserComments(null);
}
}
return $this;
}
}
答案 0 :(得分:3)
您不需要任何"自定义逻辑"代码,只需使用
// Articles.php
/**
* @ORM\OneToMany(targetEntity="App\Entity\Comments", mappedBy="articleComments", cascade={"remove"})
*/
private $comments;
因此,当您删除article
时,也会删除相关的评论。
此注释是ORM
,因此它仅适用于您的应用程序逻辑。如果你想把它也放在@DBMS级别,只需添加
@ORM\JoinColumn(name="comments_id", referencedColumnName="id", onDelete="CASCADE")
你和两个都有。
只是一个注意事项:从db表中创建多个名称并不常见。在我使用JoinColumn
的示例中,我使用了comments
(复数),但您必须验证名称是否与实际列名称匹配,或者至少使用您想要的名称进行验证。
回到您的问题,您需要验证评论是否为null
并尝试将其删除。这里有很多错误:首先你在文章的路线上,并且你正在用文章id
作为主键搜索评论(因此在概念上这是错误的)。
其次,您尝试删除null
变量。
你可以在这里做的是摆脱该控制器的所有代码注释代码并执行类似这样的操作
/**
* @Route("admin/supprimer/{id}")
* @param int $id
* @return Response
*/
public function delete(int $id): Response {
$article = $this->getDoctrine()
->getRepository(Articles::class)
->find($id);
$manager = $this->getDoctrine()->getManager();
foreach ($article->getComments() as $comment) {
$manager->remove($comment);
}
$manager->remove($article);
$manager->flush();
$this->addFlash('deleteArticle', 'L\'article a bien étais supprimer');
return $this->redirectToRoute('app_backoffice_admin');
}
最后,但并非最不重要的是,您可以直接为Article
键入提示,它将由Symfony ParamConvert解析
/**
* @Route("admin/supprimer/{id}")
* @param int $id
* @return Response
*/
public function delete(Article $article): Response {
$manager = $this->getDoctrine()->getManager();
foreach ($article->getComments() as $comment) {
$manager->remove($comment);
}
$manager->remove($article);
$manager->flush();
$this->addFlash('deleteArticle', 'L\'article a bien étais supprimer');
return $this->redirectToRoute('app_backoffice_admin');
}