1: <?php
2: namespace TIC\DormBundle\Base;
3:
4: use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
5: use Doctrine\Persistence\ManagerRegistry;
6: use Doctrine\ORM\EntityRepository;
7: use Doctrine\ORM\QueryBuilder;
8:
9: /**
10: * Repository de base disposant de nombreuses méthodes utiles.
11: * @see https://symfony.com/doc/current/doctrine.html#doctrine-queries
12: *
13: * @TODO ajouter des méthodes saveEntity et deleteEntity
14: * à défaut de charger l'ensemble du ManagerTrait
15: * (problématique car _em déjà présent et getRepo/getItem spécifiques)
16: */
17: abstract class TICRepository extends ServiceEntityRepository
18: {
19:
20: // Initialisation automatique des propriétés à partir du nom de la classe du controlleur
21: # use \TIC\CoreBundle\Traits\ContextProperties;
22: # use \TIC\DormBundle\Traits\ManagerTrait;
23: use \TIC\DormBundle\Traits\RepositoryFilterable;
24:
25: /**
26: * Construction du Repository en renseignant automatiquement l'entité associée.
27: */
28: public function __construct(ManagerRegistry $registry)
29: {
30: $entityClass = \str_replace("\\Repository\\", "\\Entity\\", static::class);
31: $entityClass = \preg_replace('/Repository$/', '', $entityClass);
32: parent::__construct($registry, $entityClass);
33: }
34:
35: /**
36: * Retourne une instance d'un autre Repository du projet.
37: *
38: * @param string $entity
39: * @return EntityRepository
40: */
41: protected function getRepo(string $entity): EntityRepository
42: {
43: $entitySpace = \preg_match('/^(.+\\\\Entity\\\\)/', $this->_entityName, $m) ? $m[1] : '';
44: return $this->_em->getRepository($entitySpace . \ucfirst($entity));
45: }
46:
47: /**
48: * Retourne une entité en fonction de sa clé primaire.
49: * Note: utilisé par la méthode getItem() des controlleurs (utile pour surcharge)
50: *
51: * @param mixed $id Valeur de la clé primaire pour l'entité recherchée
52: * @return Entity Retourne l'entité correspondante (ou NULL sinon)
53: */
54: public function getItem($id): ?object
55: {
56: return $this->find($id);
57: }
58:
59: /**
60: * Recherche des valeurs existantes d'un champs (avec motif de filtrage cf typeahead).
61: *
62: * @param string $field Nom du champs pour la récupération des valeurs
63: * @param string $term Terme de recherche pour filtrage des résultats
64: * @param integer $minOccurs Nombre minimum d'occurence d'une valeur pour être proposée
65: * @return array Liste des différentes valeurs correspondantes
66: */
67: public function getFieldValues(string $field, string $term = '', int $minOccurs = 0): array
68: {
69: $field = 'a.' . $field;
70: if (! $minOccurs) $qb = $this->createQueryBuilder('a')
71: ->select('DISTINCT(' . $field . ')')
72: ->where($field . ' IS NOT NULL')->andWhere($field . ' != \'\'')
73: ->orderBy($field, 'ASC')
74: ;
75: else $qb = $this->createQueryBuilder('a')
76: ->select($field)->groupBy($field)
77: ->where($field . ' IS NOT NULL')->andWhere($field . ' != \'\'')
78: ->having('COUNT(' . $field . ') >= :min')->setParameter('min', $minOccurs)
79: ->orderBy($field, 'ASC')
80: ;
81: if ($term !== '') $qb
82: ->andWhere($field . ' LIKE :term')
83: ->setParameter('term', '%' . $term . '%')
84: ;
85: return $qb->getQuery()->getResult('column');
86: }
87:
88: /**
89: * Génération d'une chaine aléatoire et unique pour une colonne indiquée.
90: *
91: * @param string $field Nom du champs à tester pour l'unicité
92: * @param integer $length Nombre de caractères à générer (longueur de la chaine)
93: * @param string $format Motif sprintf (avec un %s) pour créer une valeur contenant la partie aléatoire
94: * @param mixed $sigils Alphabet à utiliser (caractères autorisés dans la chaine)
95: * si Null : ensemble alpha-numérique [a-zA-Z0-9]
96: * si True : ASCII de base imprimable, sauf & < > $ ^ " ' ` \ |
97: * si False : alpha-numérique non ambigus [A-Z0-9], sauf 0 O 1 I
98: * @return string Chaine constituée de $length caractères aléatoires parmis $sigils
99: */
100: public function genUniqueRandom(string $field, int $length = 8, string $format = null, mixed $sigils = null): string
101: {
102: // limite au nombre de valeurs générées et testées par sécurité
103: $max_try = 1000;
104: while (true) {
105: // génération d'une chaine aléatoire formattée
106: $str = \TIC\CoreBundle\Util\StringHelper::genrandom($length, $sigils);
107: if (\is_string($format) && (\strpos($format, '%s') !== false)) $str = \sprintf($format, $str);
108:
109: // vérification de l'unicité dans la table
110: $res = $this->createQueryBuilder('a')->select('COUNT(a)')
111: ->where('a.' . $field . ' = :str')->setParameter('str', $str)
112: ->getQuery()->getSingleScalarResult();
113: if (! $res) break;
114: if (--$max_try < 1) throw new \Exception("Can't generate unique random value for " . $field);
115: }
116: return $str;
117: }
118:
119: }
120: