Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A [SoftDeleteable] cycle has been detected, so a topological sort is not possible. The getCycle() method provides the list of nodes that form the cycle. #2795

Open
imajim opened this issue Apr 25, 2024 · 0 comments

Comments

@imajim
Copy link

imajim commented Apr 25, 2024

Hello,
i have an issue with sofrdelete on Symfony 6.3 and doctrine extension 3 softdeleteable

i would like soft delete an entity User but i've got a doctrine error :

image Could you help me ? Thx ^^

UserController :

#[Route("/delete/{userId}", name: "app_admin_deleteUser", methods: ["POST"])]
    public function deleteUser(Request $request, $userId)
    {

        $user = $this->em->getRepository(AdminUser::class)->find($userId);
        $formDelete = $this->createDeleteForm($user);
        $formDelete->handleRequest($request);
        if ($formDelete->isSubmitted() && $formDelete->isValid()) {
            $this->em->remove($user);
            $this->em->flush();
            $this->session->getFlashBag()->add('success', 'Utilisateur supprimé.');

        }

        return $this->redirectToRoute('app_admin_users');

    }

My User Entity :

<?php

namespace App\Entity\Admin;

use App\Classes\AdminUserTrait;
use App\Entity\Application\AdminUserExtraData;
use App\Entity\Application\Connection;
use App\Entity\Application\Dossier;
use App\Entity\Application\DossierConsultation;
use App\Entity\Application\Evenement;
use App\Entity\Application\Invitation;
use App\Entity\Application\Notification;
use App\Entity\Application\Prospect;
use App\Repository\Admin\AdminUserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Webingco\AdminBundle\Entity\AdminUserModel as BaseAdminUser;

#[ORM\Entity(repositoryClass: AdminUserRepository::class)]
#[Gedmo\SoftDeleteable(fieldName: 'deletedAt', timeAware: false, hardDelete: true)]
class AdminUser extends BaseAdminUser
{
    use AdminUserTrait;
    public $level;
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    #[ORM\OneToMany(targetEntity: Dossier::class, mappedBy: 'commercial', orphanRemoval: true)]
    private $dossiers;

    #[ORM\OneToOne(targetEntity: AdminUserExtraData::class, mappedBy: 'adminUser', cascade: ['persist', 'remove'])]
    private $adminUserExtraData;

    #[ORM\JoinTable(name: 'admin_user_responsables')]
    #[ORM\ManyToMany(targetEntity: AdminUser::class, inversedBy: 'commerciaux')]
    private $responsables;

    #[ORM\ManyToMany(targetEntity: AdminUser::class, mappedBy: 'responsables')]
    private $commerciaux;

    #[ORM\OneToMany(mappedBy: 'user', targetEntity: Notification::class, orphanRemoval: true)]
    private $notifications;

    #[ORM\OneToMany(mappedBy: 'user', targetEntity: DossierConsultation::class, orphanRemoval: true)]
    private $dossierConsultations;

    #[ORM\OneToOne(mappedBy: 'user', targetEntity: Connection::class, cascade: ['persist', 'remove'])]
    private $connection;

    #[ORM\OneToMany(mappedBy: 'user', targetEntity: Prospect::class, orphanRemoval: true)]
    private $prospects;

    #[ORM\OneToMany(mappedBy: 'user', targetEntity: Invitation::class, orphanRemoval: true)]
    private $invitations;

    #[ORM\ManyToMany(targetEntity: AdminUser::class, mappedBy: 'prospecteursCommerciaux')]
    private Collection $prospecteurs;

    #[ORM\JoinTable(name: 'admin_user_prospecteurs_commerciaux')]
    #[ORM\JoinColumn(name: 'prospecteur_id')]
    #[ORM\InverseJoinColumn(name: 'commercial_id')]
    #[ORM\ManyToMany(targetEntity: AdminUser::class, inversedBy: 'prospecteurs')]
    private Collection $prospecteursCommerciaux;

    #[ORM\OneToMany(mappedBy: 'user', targetEntity: Evenement::class, orphanRemoval: true)]
    private $evenements;

    #[ORM\Column(name: 'deletedAt', type: Types::DATETIME_MUTABLE, nullable: true)]
    private $deletedAt;

    public function __construct()
    {
        $this->dossiers = new ArrayCollection();
        $this->responsables = new ArrayCollection();
        $this->commerciaux = new ArrayCollection();
        $this->notifications = new ArrayCollection();
        $this->dossierConsultations = new ArrayCollection();
        $this->prospects = new ArrayCollection();
        $this->invitations = new ArrayCollection();
        $this->prospecteursCommerciaux = new ArrayCollection();
        $this->prospecteurs = new ArrayCollection();
        $this->evenements = new ArrayCollection();
    }
....
    public function getDeletedAt(): ?\DateTime
    {
        return $this->deletedAt;
    }

    public function setDeletedAt(?\DateTime $deletedAt): self
    {
        $this->deletedAt = $deletedAt;
        return $this;
    }

}

AdminUserModel Entity Superclass :

<?php

namespace Webingco\AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Gedmo\Mapping\Annotation as Gedmo;
use Webingco\AdminBundle\Classes\AdminUserTrait;

#[ORM\MappedSuperclass]
#[UniqueEntity(fields: ['email'], message: 'Cette adresse email est déja utilisée.')]
class AdminUserModel implements UserInterface, PasswordAuthenticatedUserInterface
{
    use AdminUserTrait;

    #[ORM\Column(type: 'string', length: 180, unique: true)]
    private $email;

    #[ORM\Column(type: 'json')]
    private $roles = [];

    /**
     * @var string The hashed password
     */
    #[ORM\Column(type: 'string')]
    private $password;

    #[ORM\Column(type: 'boolean')]
    private $isVerified = false;

    #[ORM\Column(type: 'boolean')]
    private $isEnabled;

    #[ORM\Column(type: 'datetime')]
    #[Gedmo\Timestampable(on: 'create')]
    private $createdAt;

    #[ORM\Column(type: 'datetime')]
    #[Gedmo\Timestampable(on: 'update')]
    private $updatedAt;

    #[ORM\Column(type: 'string', length: 100, nullable: true)]
    private $lastname;

    #[ORM\Column(type: 'string', length: 100, nullable: true)]
    private $firstname;

    #[ORM\Column(type: 'string', length: 20, nullable: true)]
    private $phone;

    #[ORM\Column(type: 'string', length: 50, nullable: true)]
    private $ip;

    #[ORM\Column(type: 'datetime', nullable: true)]
    private $lastLogin;

    private $plainPassword = null;
   
...

}

Doctrine.yaml :

doctrine:
    dbal:
        password: '%env(DATABASE_PASSWORD)%'
        url: '%env(resolve:DATABASE_URL)%'

        # IMPORTANT: You MUST configure your server version,
        # either here or in the DATABASE_URL env var (see .env file)
        #server_version: '13'
    orm:
        filters:
            softdeleteable:
                class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
                enabled: true
        dql:
            string_functions:
                JSON_CONTAINS: Scienta\DoctrineJsonFunctions\Query\AST\Functions\Mysql\JsonContains
                FIELD: DoctrineExtensions\Query\Mysql\Field
        auto_generate_proxy_classes: true
        naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
        auto_mapping: true
        report_fields_where_declared: true
        mappings:
            gedmo_tree:
                prefix: Gedmo\Tree\Entity
                dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Tree/Entity"
                alias: GedmoTree # (optional) it will default to the name set for the mapping
                is_bundle: false
            App:
                is_bundle: false
                dir: '%kernel.project_dir%/src/Entity'
                prefix: 'App\Entity'
                alias: App

stof_doctrine_extensions.yaml :

stof_doctrine_extensions:
    default_locale: fr_FR
    orm:
        default:
            sluggable: true
            timestampable: true
            tree: true
            softdeleteable: true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant