From 6d7e504dee18a1a9388666c1300431f828984c34 Mon Sep 17 00:00:00 2001 From: Nathan Boiron Date: Mon, 29 Jun 2026 09:51:24 +0200 Subject: [PATCH] =?UTF-8?q?Ajout=20d'une=20entit=C3=A9=20parente=20pour=20?= =?UTF-8?q?l'id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...R-003-doctrine-entity-mapped-superclass.md | 118 ++++++++++++++++++ phpstan-baseline.php | 12 -- .../AppBundle/Accounting/Entity/Account.php | 8 +- .../AppBundle/Accounting/Entity/Category.php | 8 +- sources/AppBundle/Accounting/Entity/Event.php | 8 +- .../AppBundle/Accounting/Entity/Operation.php | 8 +- .../AppBundle/Accounting/Entity/Payment.php | 8 +- .../AppBundle/Accounting/Entity/Produit.php | 8 +- sources/AppBundle/Accounting/Entity/Rule.php | 8 +- .../AssembleeGenerale/Entity/Presence.php | 8 +- .../AssembleeGenerale/Entity/Question.php | 8 +- .../Association/Entity/Utilisateur.php | 8 +- sources/AppBundle/Doctrine/Entity.php | 21 ++++ sources/AppBundle/Site/Entity/Article.php | 8 +- sources/AppBundle/Site/Entity/Feuille.php | 8 +- sources/AppBundle/Site/Entity/Rubrique.php | 8 +- .../SuperApero/Entity/SuperApero.php | 8 +- .../SuperApero/Entity/SuperAperoMeetup.php | 8 +- .../SuperApero/Form/SuperAperoType.php | 32 +++-- sources/AppBundle/Veille/Entity/Envoi.php | 8 +- .../Entity/NewsletterDesinscription.php | 8 +- .../Veille/Entity/NewsletterInscription.php | 8 +- templates/admin/site/article_form.html.twig | 2 +- 23 files changed, 197 insertions(+), 132 deletions(-) create mode 100644 doc/decisions/ADR-003-doctrine-entity-mapped-superclass.md create mode 100644 sources/AppBundle/Doctrine/Entity.php diff --git a/doc/decisions/ADR-003-doctrine-entity-mapped-superclass.md b/doc/decisions/ADR-003-doctrine-entity-mapped-superclass.md new file mode 100644 index 000000000..92367ee59 --- /dev/null +++ b/doc/decisions/ADR-003-doctrine-entity-mapped-superclass.md @@ -0,0 +1,118 @@ +--- +Id: ADR-003 +Date: 2026-06-29 +Statut: Proposé +--- + +# Les entités Doctrine héritent d'une classe parente + +## Contexte + +Avec l'ajout de la baseline PHPStan et le passage au niveau 10, il y a pas mal d'endroits dans le code où l'id nullable +des entités pose problème. + +Par exemple, quand on récupère une liste d'entités depuis un repository, on sait que l'id est présent, mais pas PHPStan +car la propriété reste nullable dans la classe de l'entité. + +Cela force des vérifications qui n'apportent pas grand chose et rendent le code plus difficile à lire et naviguer. + +Par exemple : + +```php +#[ORM\Entity] +#[ORM\Table(name: 'exemple')] +class Entity +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column] + public ?int $id = null; + + #[ORM\Column(length: 255, nullable: true)] + public string $foo = null; +} + +class ExampleRepository +{ + /** + * @return array + */ + public function all(): array { /* return ... */ } +} + +$entities = $exempleRepository->all(); + +$map = []; +foreach ($entities as $entity) { + // Cette ligne va déclencher une erreur PHPStan car l'id pourrait être nullable, + // alors qu'on sait ici que ce n'est pas le cas. + $map[$entity->id] = $entity->foo; + + // Il faudrait faire ça à chaque fois : + if ($entity->id === null) { + continue; + } + + $map[$entity->id] = $entity->foo; +} +``` + +## Décision + +Les entités Doctrine héritent d'une classe abstraite contenant l'id et une méthode pour vérifier sa présence. + +Cela permet à PHPStan de mieux analyser le code, tout en conservant une certaine sécurité. Si une entité n'est pas +persistée et qu'on tente de lire son id, cela déclenche une erreur. + +### Détails d'implémentation + +```php +use AppBundle\Doctrine\Entity; +use Doctrine\ORM\Mapping as ORM; + +#[ORM\Entity] +#[ORM\Table(name: 'exemple')] +class Exemple extends Entity +{ + #[ORM\Column(length: 255, nullable: false)] + public string $nonNullbale; + + #[ORM\Column(length: 255, nullable: true)] + public ?string $nullable = null; +} +``` + +Et à l'utilisation : + +```php +if ($exemple->isPersisted()) { + // $exemple->id est initialisé et non-null +} +``` + +## Alternatives considérées + +1. **Un trait** : C'est plus difficile et lent à analyser pour PHPStan qu'une classe parente. +2. **Vérifier l'id à chaque fois** : Le code devient moins lisible pour peu d'intérêt. + +## Conséquences + +### Positives + +Quand on récupère une ou plusieurs entités depuis la base de données, plus besoin de vérifier la présence de l'id dans +l'instance. + +Si on tente d'accéder à l'id d'une entité à un endroit non vérifié, une erreur survient fort et au bon endroit (au lieu +de trimballer un `null` plus loin dans le code). + +### Négatives + +Toutes les entités doivent hériter d'une classe parente. + +Cela ne fonctionne qu'avec des entités qui ont un id entier auto-incrément. + +## Références + +Analyse des traits par PHPStan : https://phpstan.org/blog/how-phpstan-analyses-traits + +Exemple PHPStan : https://phpstan.org/r/3f3354d7-d6f5-4493-bfbd-3f7a37cf8d32 diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 30c4b3e7c..b5ed59d7a 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -115,18 +115,6 @@ 'count' => 1, 'path' => __DIR__ . '/sources/Afup/Corporate/Page.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Parameter \\#1 \\$parentId of method AppBundle\\\\Site\\\\Entity\\\\Repository\\\\FeuilleRepository\\:\\:getFeuillesEnfant\\(\\) expects int, int\\|null given\\.$#', - 'identifier' => 'argument.type', - 'count' => 3, - 'path' => __DIR__ . '/sources/Afup/Corporate/Page.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Possibly invalid array key type int\\|null\\.$#', - 'identifier' => 'offsetAccess.invalidOffset', - 'count' => 1, - 'path' => __DIR__ . '/sources/Afup/Corporate/Page.php', -]; $ignoreErrors[] = [ 'message' => '#^Cannot access offset \'elements\' on mixed\\.$#', 'identifier' => 'offsetAccess.nonOffsetAccessible', diff --git a/sources/AppBundle/Accounting/Entity/Account.php b/sources/AppBundle/Accounting/Entity/Account.php index 38d87ba42..824bed8b6 100644 --- a/sources/AppBundle/Accounting/Entity/Account.php +++ b/sources/AppBundle/Accounting/Entity/Account.php @@ -4,17 +4,13 @@ namespace AppBundle\Accounting\Entity; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'compta_compte')] -class Account +class Account extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(name: 'nom_compte', length: 45, nullable: false)] public string $name; diff --git a/sources/AppBundle/Accounting/Entity/Category.php b/sources/AppBundle/Accounting/Entity/Category.php index 98072f573..c8c909b76 100644 --- a/sources/AppBundle/Accounting/Entity/Category.php +++ b/sources/AppBundle/Accounting/Entity/Category.php @@ -4,17 +4,13 @@ namespace AppBundle\Accounting\Entity; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'compta_categorie')] -class Category +class Category extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(name: 'categorie', length: 255, nullable: false)] public string $name; diff --git a/sources/AppBundle/Accounting/Entity/Event.php b/sources/AppBundle/Accounting/Entity/Event.php index d6110ac23..dd754ccaf 100644 --- a/sources/AppBundle/Accounting/Entity/Event.php +++ b/sources/AppBundle/Accounting/Entity/Event.php @@ -4,17 +4,13 @@ namespace AppBundle\Accounting\Entity; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'compta_evenement')] -class Event +class Event extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(name: 'evenement', length: 50, nullable: false)] public string $name; diff --git a/sources/AppBundle/Accounting/Entity/Operation.php b/sources/AppBundle/Accounting/Entity/Operation.php index cf3fe01ce..b5482c2dd 100644 --- a/sources/AppBundle/Accounting/Entity/Operation.php +++ b/sources/AppBundle/Accounting/Entity/Operation.php @@ -4,17 +4,13 @@ namespace AppBundle\Accounting\Entity; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'compta_operation')] -class Operation +class Operation extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(name: 'operation', length: 255, nullable: false)] public string $name; } diff --git a/sources/AppBundle/Accounting/Entity/Payment.php b/sources/AppBundle/Accounting/Entity/Payment.php index 2cc9a5899..4411c3695 100644 --- a/sources/AppBundle/Accounting/Entity/Payment.php +++ b/sources/AppBundle/Accounting/Entity/Payment.php @@ -4,17 +4,13 @@ namespace AppBundle\Accounting\Entity; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'compta_reglement')] -class Payment +class Payment extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(name: 'reglement', length: 50, nullable: false)] public string $name; diff --git a/sources/AppBundle/Accounting/Entity/Produit.php b/sources/AppBundle/Accounting/Entity/Produit.php index 6748582e4..93e238767 100644 --- a/sources/AppBundle/Accounting/Entity/Produit.php +++ b/sources/AppBundle/Accounting/Entity/Produit.php @@ -5,17 +5,13 @@ namespace AppBundle\Accounting\Entity; use AppBundle\Accounting\TvaTaux; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'compta_produit')] -class Produit +class Produit extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(length: 255, nullable: false)] public string $reference; diff --git a/sources/AppBundle/Accounting/Entity/Rule.php b/sources/AppBundle/Accounting/Entity/Rule.php index df6377f27..232f86899 100644 --- a/sources/AppBundle/Accounting/Entity/Rule.php +++ b/sources/AppBundle/Accounting/Entity/Rule.php @@ -4,17 +4,13 @@ namespace AppBundle\Accounting\Entity; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'compta_regle')] -class Rule +class Rule extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(length: 255, nullable: false)] public string $label; diff --git a/sources/AppBundle/AssembleeGenerale/Entity/Presence.php b/sources/AppBundle/AssembleeGenerale/Entity/Presence.php index 475a00387..05214e343 100644 --- a/sources/AppBundle/AssembleeGenerale/Entity/Presence.php +++ b/sources/AppBundle/AssembleeGenerale/Entity/Presence.php @@ -6,18 +6,14 @@ use AppBundle\AssembleeGenerale\Enum\PresenceEtat; use AppBundle\Association\Entity\Utilisateur; +use AppBundle\Doctrine\Entity; use AppBundle\Doctrine\Type\UnixTimestampType; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'afup_presences_assemblee_generale')] -class Presence +class Presence extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(type: UnixTimestampType::NAME, nullable: false)] public \DateTime $date; diff --git a/sources/AppBundle/AssembleeGenerale/Entity/Question.php b/sources/AppBundle/AssembleeGenerale/Entity/Question.php index abaf63289..36a4a069a 100644 --- a/sources/AppBundle/AssembleeGenerale/Entity/Question.php +++ b/sources/AppBundle/AssembleeGenerale/Entity/Question.php @@ -6,18 +6,14 @@ use AppBundle\AssembleeGenerale\Enum\QuestionEtat; use AppBundle\AssembleeGenerale\Enum\VoteValeur; +use AppBundle\Doctrine\Entity; use AppBundle\Doctrine\Type\UnixTimestampType; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'afup_assemblee_generale_question')] -class Question +class Question extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(type: UnixTimestampType::NAME, nullable: true)] public ?\DateTime $date = null; diff --git a/sources/AppBundle/Association/Entity/Utilisateur.php b/sources/AppBundle/Association/Entity/Utilisateur.php index ab4cf3e9e..626037d3c 100644 --- a/sources/AppBundle/Association/Entity/Utilisateur.php +++ b/sources/AppBundle/Association/Entity/Utilisateur.php @@ -4,17 +4,13 @@ namespace AppBundle\Association\Entity; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'afup_personnes_physiques')] -class Utilisateur +class Utilisateur extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(length: 255, nullable: true)] public ?string $email = null; } diff --git a/sources/AppBundle/Doctrine/Entity.php b/sources/AppBundle/Doctrine/Entity.php new file mode 100644 index 000000000..50efa17f1 --- /dev/null +++ b/sources/AppBundle/Doctrine/Entity.php @@ -0,0 +1,21 @@ +id); + } +} diff --git a/sources/AppBundle/Site/Entity/Article.php b/sources/AppBundle/Site/Entity/Article.php index b5001e3d5..8730cce26 100644 --- a/sources/AppBundle/Site/Entity/Article.php +++ b/sources/AppBundle/Site/Entity/Article.php @@ -4,6 +4,7 @@ namespace AppBundle\Site\Entity; +use AppBundle\Doctrine\Entity; use AppBundle\Doctrine\Type\UnixTimestampType; use AppBundle\Site\Enum\ArticleTheme; use AppBundle\Site\Enum\ArticleEtat; @@ -11,13 +12,8 @@ #[ORM\Entity] #[ORM\Table(name: 'afup_site_article')] -class Article +class Article extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\ManyToOne(targetEntity: Rubrique::class)] #[ORM\JoinColumn(name: 'id_site_rubrique', referencedColumnName: 'id', nullable: true)] public ?Rubrique $rubrique = null; diff --git a/sources/AppBundle/Site/Entity/Feuille.php b/sources/AppBundle/Site/Entity/Feuille.php index a825bbd88..13a387671 100644 --- a/sources/AppBundle/Site/Entity/Feuille.php +++ b/sources/AppBundle/Site/Entity/Feuille.php @@ -4,18 +4,14 @@ namespace AppBundle\Site\Entity; +use AppBundle\Doctrine\Entity; use AppBundle\Doctrine\Type\UnixTimestampType; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'afup_site_feuille')] -class Feuille +class Feuille extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(nullable: true)] public ?int $idParent = null; diff --git a/sources/AppBundle/Site/Entity/Rubrique.php b/sources/AppBundle/Site/Entity/Rubrique.php index ec8248041..dfaba0a2e 100644 --- a/sources/AppBundle/Site/Entity/Rubrique.php +++ b/sources/AppBundle/Site/Entity/Rubrique.php @@ -4,12 +4,13 @@ namespace AppBundle\Site\Entity; +use AppBundle\Doctrine\Entity; use AppBundle\Doctrine\Type\UnixTimestampType; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'afup_site_rubrique')] -class Rubrique +class Rubrique extends Entity { public const int ID_RUBRIQUE_ACTUALITES = 9; public const int ID_RUBRIQUE_FORUM = 52; @@ -18,11 +19,6 @@ class Rubrique public const int ID_RUBRIQUE_INFORMATIONS_PRATIQUES = 86; public const int ID_RUBRIQUE_NOS_ACTIONS = 88; - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(nullable: true)] public ?int $idParent = null; diff --git a/sources/AppBundle/SuperApero/Entity/SuperApero.php b/sources/AppBundle/SuperApero/Entity/SuperApero.php index 590c59719..1a29b544a 100644 --- a/sources/AppBundle/SuperApero/Entity/SuperApero.php +++ b/sources/AppBundle/SuperApero/Entity/SuperApero.php @@ -4,6 +4,7 @@ namespace AppBundle\SuperApero\Entity; +use AppBundle\Doctrine\Entity; use DateTimeImmutable; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; @@ -12,13 +13,8 @@ #[ORM\Entity] #[ORM\Table(name: 'super_apero')] -class SuperApero +class SuperApero extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(type: 'date_immutable', nullable: false)] public DateTimeImmutable $date; diff --git a/sources/AppBundle/SuperApero/Entity/SuperAperoMeetup.php b/sources/AppBundle/SuperApero/Entity/SuperAperoMeetup.php index 074dac3f3..9090fe855 100644 --- a/sources/AppBundle/SuperApero/Entity/SuperAperoMeetup.php +++ b/sources/AppBundle/SuperApero/Entity/SuperAperoMeetup.php @@ -4,17 +4,13 @@ namespace AppBundle\SuperApero\Entity; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'super_apero_meetup')] -class SuperAperoMeetup +class SuperAperoMeetup extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\ManyToOne(targetEntity: SuperApero::class, inversedBy: 'meetups')] #[ORM\JoinColumn(nullable: false)] public SuperApero $superApero; diff --git a/sources/AppBundle/SuperApero/Form/SuperAperoType.php b/sources/AppBundle/SuperApero/Form/SuperAperoType.php index 63b5eaaa4..2feacad43 100644 --- a/sources/AppBundle/SuperApero/Form/SuperAperoType.php +++ b/sources/AppBundle/SuperApero/Form/SuperAperoType.php @@ -57,23 +57,33 @@ public function buildForm(FormBuilderInterface $builder, array $options): void } }); - $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($antennes): void { + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event): void { /** @var SuperApero $superApero */ $superApero = $event->getData(); - $form = $event->getForm(); - if (isset($superApero->date)) { - $year = $superApero->annee(); - $existing = $this->superAperoRepository->findOneByYear($year); + if (!isset($superApero->date)) { + return; + } - if ($existing !== null && $existing->id !== $superApero->id) { - $form->get('date')->addError( - new FormError("Un Super Apéro existe déjà pour l'année {$year}."), - ); - } + $year = $superApero->annee(); + $existing = $this->superAperoRepository->findOneByYear($year); + + if ($existing === null) { + return; + } + + if (!$superApero->isPersisted() || $existing->id !== $superApero->id) { + $event->getForm()->get('date')->addError( + new FormError("Un Super Apéro existe déjà pour l'année {$year}."), + ); } + }); + + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($antennes): void { + /** @var SuperApero $superApero */ + $superApero = $event->getData(); - $meetupsForm = $form->get('meetups'); + $meetupsForm = $event->getForm()->get('meetups'); $submittedAntennes = []; foreach ($antennes as $antenne) { diff --git a/sources/AppBundle/Veille/Entity/Envoi.php b/sources/AppBundle/Veille/Entity/Envoi.php index 2f2a9a1c9..275893555 100644 --- a/sources/AppBundle/Veille/Entity/Envoi.php +++ b/sources/AppBundle/Veille/Entity/Envoi.php @@ -4,18 +4,14 @@ namespace AppBundle\Veille\Entity; +use AppBundle\Doctrine\Entity; use AppBundle\Veille\Entity\Repository\EnvoiRepository; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: EnvoiRepository::class)] #[ORM\Table(name: 'afup_techletter')] -class Envoi +class Envoi extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(name: 'sending_date', type: 'datetime')] public \DateTimeInterface $dateEnvoi; diff --git a/sources/AppBundle/Veille/Entity/NewsletterDesinscription.php b/sources/AppBundle/Veille/Entity/NewsletterDesinscription.php index 9b2f39ba9..0e9c8f918 100644 --- a/sources/AppBundle/Veille/Entity/NewsletterDesinscription.php +++ b/sources/AppBundle/Veille/Entity/NewsletterDesinscription.php @@ -4,17 +4,13 @@ namespace AppBundle\Veille\Entity; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'afup_techletter_unsubscriptions')] -class NewsletterDesinscription +class NewsletterDesinscription extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\Column(length: 255, nullable: true)] public ?string $email = null; diff --git a/sources/AppBundle/Veille/Entity/NewsletterInscription.php b/sources/AppBundle/Veille/Entity/NewsletterInscription.php index b9cd0da6b..5fd9d459a 100644 --- a/sources/AppBundle/Veille/Entity/NewsletterInscription.php +++ b/sources/AppBundle/Veille/Entity/NewsletterInscription.php @@ -5,17 +5,13 @@ namespace AppBundle\Veille\Entity; use AppBundle\Association\Entity\Utilisateur; +use AppBundle\Doctrine\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'afup_techletter_subscriptions')] -class NewsletterInscription +class NewsletterInscription extends Entity { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - public ?int $id = null; - #[ORM\ManyToOne(targetEntity: Utilisateur::class)] #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: true)] public ?Utilisateur $user = null; diff --git a/templates/admin/site/article_form.html.twig b/templates/admin/site/article_form.html.twig index d35de261f..7a51db3ab 100644 --- a/templates/admin/site/article_form.html.twig +++ b/templates/admin/site/article_form.html.twig @@ -5,7 +5,7 @@ {% block content %}

{{ formTitle }}

- {% if article.slug != '-' %} + {% if article.persisted %}