1: <?php
2: namespace TIC\DormBundle\Traits;
3:
4: use Doctrine\ORM\EntityManagerInterface;
5: use Doctrine\ORM\EntityRepository;
6:
7: use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
8:
9: /**
10: * Injection du manager Doctrine + méthodes utilitaires pour gérer les entités :
11: * notamment getRepo(), getItem(), saveEntity() et deleteEntity()
12: */
13: trait ManagerTrait
14: {
15: // Initialisation automatique des propriétés à partir du nom de la classe courante
16: use \TIC\CoreBundle\Traits\ContextProperties; // ctxRoot, ctxName & ctxMesg
17:
18: /**
19: * @var EntityManagerInterface
20: */
21: protected $em;
22:
23: /**
24: * DI avec auto-wiring (inutile de définir le "call" sur le service grace à l'attribut @required).
25: * @see https://symfony.com/doc/current/service_container/injection_types.html#setter-injection
26: * @see https://symfony.com/doc/current/service_container/autowiring.html#autowiring-other-methods-e-g-setters-and-public-typed-properties
27: *
28: * @required
29: */
30: public function setEntityManager(EntityManagerInterface $manager): void
31: {
32: $this->em = $manager;
33: }
34:
35: /**
36: * Désactivation du journal de l'ORM (optimisation en cas de nombreuses requêtes).
37: */
38: public function EmDisableLogger(): void
39: {
40: $this->em->getConnection()->getConfiguration()->setSQLLogger(null);
41: }
42:
43: /**
44: * Désactivation d'un filtre de l'ORM (seulement si l'extension est activée).
45: */
46: public function EmDisableFilter(string $filter): bool
47: {
48: # $this->em->getFilters()->disable($filter);
49: $filters = $this->em->getFilters();
50: if (\array_key_exists($filter, $filters->getEnabledFilters())) {
51: $filters->disable($filter);
52: return true;
53: }
54: return false;
55: }
56:
57: /**
58: * Activation d'un filtre de l'ORM (seulement si l'extension est désactivée).
59: */
60: public function EmEnableFilter(string $filter): bool
61: {
62: # $this->em->getFilters()->enable($filter);
63: $filters = $this->em->getFilters();
64: if (\array_key_exists($filter, $filters->getDisabledFilters())) {
65: $filters->enable($filter);
66: return true;
67: }
68: return false;
69: }
70:
71: /**
72: * Raccourci pour obtenir le repository d'une entité (en utilisant le contexte de la classe).
73: *
74: * @param string|null $itemName Nom court de l'entité (par défaut celle associée à la classe courante)
75: * ou nom complet (si besoin d'un repository provenant d'un autre bundle)
76: * @return EntityRepository
77: */
78: protected function getRepo(?string $itemName = null): EntityRepository
79: {
80: if ($itemName === null)
81: $entityClass = $this->ctxRoot . "\\Entity\\" . $this->ctxName;
82: elseif (!str_contains($itemName, "\\"))
83: $entityClass = $this->ctxRoot . "\\Entity\\" . \ucfirst($itemName);
84: else
85: $entityClass = $itemName;
86:
87: return $this->em->getRepository($entityClass);
88: }
89:
90: /**
91: * Raccourci pour rechercher dans la BdD l'instance de l'entité correspondant à la clé donnée.
92: *
93: * @param mixed $primary Clé primaire (id) ou null pour création d'une instance
94: * @param bool $no_exception Ne pas lancer d'exception si l'entité n'est pas trouvée (retourne null)
95: * @return object|null Instance de l'entité créée ou récupérée selon la clé primaire
96: */
97: protected function getItem(mixed $primary = null, ?bool $no_exception = false): ?object
98: {
99: // create
100: if (null === $primary) {
101: $entityClass = $this->ctxRoot . "\\Entity\\" . $this->ctxName;
102: return new $entityClass();
103: }
104:
105: // update
106: $entity = $this->getRepo()->getItem($primary);
107: if (\is_object($entity)) return $entity;
108:
109: // notfound
110: if (empty($no_exception)) {
111: $message = 'error.' . $this->ctxMesg . '.object_not_found';
112: if (\method_exists($this, "trans")) $message = $this->trans($message);
113: # throw $this->createNotFoundException($message); // dispo uniquement sur controller
114: throw new NotFoundHttpException($message);
115: }
116: return null;
117: }
118:
119: /**
120: * Exécution de l'enregistrement d'une entité en BdD.
121: *
122: * @param object $entity Entité à enregistrer
123: * @return string|null Message d'erreur ou null en cas de succès
124: */
125: protected function saveEntity(object $entity): ?string
126: {
127: try {
128: # if (\method_exists($entity, 'hookSave')) $entity->hookSave();
129: $this->em->persist($entity);
130: $this->em->flush();
131: } catch (\Exception $e) {
132: return $e->getMessage();
133: }
134: return null;
135: }
136:
137: /**
138: * Exécution de la suppression d'une entité en BdD.
139: *
140: * @param object $entity Entité à supprimer
141: * @return string|null Message d'erreur ou null en cas de succès
142: */
143: protected function deleteEntity(object $entity): ?string
144: {
145: try {
146: # if (\method_exists($entity, 'hookDelete')) $entity->hookDelete();
147: $this->em->remove($entity);
148: $this->em->flush();
149: } catch (\Exception $e) {
150: return $e->getMessage();
151: }
152: return null;
153: }
154:
155: /**
156: * Exécution de la suppression d'une entité en BdD en coupant si possible le softdelete.
157: *
158: * @param object $entity Entité à supprimer
159: * @return string|null Message d'erreur ou null en cas de succès
160: */
161: protected function harddeleteEntity(object $entity): ?string
162: {
163: $hasFilter = $this->EmDisableFilter('softdeleteable');
164: $rc = $this->deleteEntity($entity);
165:
166: if ($hasFilter) {
167: $this->EmEnableFilter('softdeleteable');
168: if ($rc !== null) return $this->deleteEntity($entity);
169: }
170:
171: return $rc;
172: }
173:
174: }
175: