Symfony удаляет статьи и комментарии

Я разрабатываю блог со статьями и системой комментариев, и я хотел бы, чтобы, когда человек в бэкэнде удаляет статью, комментарии к статье также удаляются, потому что комментарий таблицы связан со статьями таблицы и пользователем таблицы.

Я просто хочу удалить статьи и комментарии к ним.

Я пробовал этот код, но он не работает, он выдает такую ​​ошибку:

EntityManager # remove () expects parameter 1 to be an entity object, NULL given.

Я пытаюсь получить комментарии с помощью геттеров и сеттеров, но он не работает и сообщает мне, что этот метод пока не существует в контроллере.

Мой контроллер:

// 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;
    }
}

С Symfony вы сможете сделать это, просто удалив свою статью, если у вас хорошие отношения между сущностями, не так ли?

Mickaël Leger 14.06.2018 12:29

Ошибка говорит: remove () expects parameter 1 to be an entity object, NULL given, а вы делаете if ($comment === null) { $comments = $this->getDoctrine()->getManager(); $comments->remove($comment);, поэтому ваша ошибка здесь: вы используете remove() на $comment, когда $comment === null, и это должен быть объект

Mickaël Leger 14.06.2018 12:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
2
1 519
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам не нужен код "настраиваемой логики", просто используйте

// 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');
 }

Большое спасибо за ваш ответ, это было пропущено каскадное удаление

Crown Backend 14.06.2018 13:13

Другие вопросы по теме