source: spip-zone/_plugins_/contacts_et_organisations/trunk/contacts_fonctions.php @ 99749

Last change on this file since 99749 was 99749, checked in by cedric@…, 3 years ago

Suppression de la table spip_organisations_contacts et basculement sur spip_organisations_liens. Suppression de la dependance au plugin editer_liens_simples

File size: 14.5 KB
Line 
1<?php
2
3/**
4 * Définition des critères, balises, filtres et fonctions
5 *
6 * @plugin Contacts & Organisations pour Spip 3.0
7 * @license GPL (c) 2009 - 2013
8 * @author Cyril Marion, Matthieu Marcillaud, Rastapopoulos
9 *
10 * @package SPIP\Contacts\Fonctions
11**/
12
13if (!defined("_ECRIRE_INC_VERSION")) return;
14
15
16
17/**
18 * Calcul de la balise `#LESORGANISATIONS`
19 *
20 * Affiche la liste des organisations d'un contact.
21 *
22 * - Soit le champs `lesauteurs` existe dans la table et à ce moment là,
23 *   on retourne son contenu
24 * - Soit la balise appelle le modele `lesorganisations.html` en lui passant
25 *   le `id_contact` dans son environnement
26 *
27 * @balise
28 *
29 * @param Champ $p
30 *     Pile au niveau de la balise
31 * @return Champ
32 *     Pile complétée par le code à générer
33 */
34function balise_LESORGANISATIONS_dist($p) {
35        // Cherche le champ 'lesorganisations' dans la pile
36        $_lesorganisations = champ_sql('lesorganisations', $p, false);
37
38        // Si le champ n'existe pas (cas de spip_contacts), on applique
39        // le modele lesorganisations.html en passant id_contact dans le contexte;
40        // dans le cas contraire on prend le champ 'lesorganisations'
41        if ($_lesorganisations
42        and $_lesorganisations != '@$Pile[0][\'lesorganisations\']') {
43                $p->code = "safehtml($_lesorganisations)";
44                // $p->interdire_scripts = true;
45        } else {
46                $connect = !$p->id_boucle ? ''
47                  : $p->boucles[$p->id_boucle]->sql_serveur;
48
49                $c = memoriser_contexte_compil($p);
50
51                $p->code = sprintf(CODE_RECUPERER_FOND, "'modeles/lesorganisations'",
52                                   "array('id_contact' => ".champ_sql('id_contact', $p) .")",
53                                   "'trim'=>true, 'compil'=>array($c)",
54                                   _q($connect));
55                $p->interdire_scripts = false; // securite apposee par recuperer_fond()
56        }
57
58        return $p;
59}
60
61
62/**
63 * Calcul de la balise `#ORGANISATIONS`
64 *
65 * @deprecated Utiliser `#LESORGANISATIONS`
66 * @balise
67 *
68 * @param Champ $p
69 *     Pile au niveau de la balise
70 * @return Champ
71 *     Pile complétée par le code à générer
72 */
73function balise_ORGANISATIONS_dist($p) {
74        $f = charger_fonction('LESORGANISATIONS', 'balise');
75        return $f($p);
76}
77
78
79/**
80 * Calcul du critère `compteur_contacts`
81 *
82 * Compter les contacts liés à une organisation, dans une boucle organisations
83 * pour la vue `prive/liste/organisations.html`
84 *
85 * @example
86 *   ```
87 *   <BOUCLE_o(ORGANISATIONS){compteur_contacts}>
88 *     [(#COMPTEUR_CONTACTS|singulier_ou_pluriel{contacts:nb_contact,contacts:nb_contacts})]
89 *   ```
90 *
91 * @note
92 *   Fonctionnement inspiré du critère `compteur_articles` dans SPIP
93 *
94 * @critere
95 *
96 * @param string $idb     Identifiant de la boucle
97 * @param array $boucles  AST du squelette
98 * @param Critere $crit   Paramètres du critère dans cette boucle
99 * @return void
100 */
101function critere_compteur_contacts_dist($idb, &$boucles, $crit) {
102        $boucle = &$boucles[$idb];
103
104        $not = "";
105        if ($crit->not)
106                $not = ", 'NOT'";
107        $boucle->from['LOC'] = 'spip_organisations_liens';
108        $boucle->from_type['LOC'] = 'LEFT';
109        $boucle->join['LOC'] = array("'organisations'","'id_organisation'","'id_organisation'");
110        $boucle->where[] = "'LOC.objet='.sql_quote('contact')";
111
112        $boucle->select[] = "COUNT(LOC.id_objet) AS compteur_contacts";
113        $boucle->group[] = 'organisations.id_organisation';
114}
115
116
117/**
118 * Calcul de la balise `#COMPTEUR_CONTACTS`
119 *
120 * Compter les contacts publiés liés à une organisation, dans une boucle organisations
121 * pour la vue `prive/liste/organisations.html`
122 *
123 * Cette balise nécessite le critère `compteur_contacts`.
124 *
125 * @balise
126 *
127 * @param Champ $p
128 *     Pile au niveau de la balise
129 * @return Champ
130 *     Pile complétée par le code à générer
131 */
132function balise_COMPTEUR_CONTACTS_dist($p) {
133        return rindex_pile($p, 'compteur_contacts', 'compteur_contacts');
134}
135
136
137
138// Correction de jointures et champs spéciaux
139// ------------------------------------------
140
141
142/**
143 * Calcul du critère `contacts_auteurs`
144 *
145 * Crée une jointure correcte entre auteurs et contacts et définit quelques
146 * champs spéciaux (nom_contact, prenom_contact, ...)
147 *
148 * @example
149 *     ```
150 *     <BOUCLE_(CONTACTS){contacts_auteurs} />
151 *     <BOUCLE_(AUTEURS){contacts_auteurs} />
152 *     ```
153 *
154 * @critere
155 *
156 * @param string $idb
157 *     Identifiant de la boucle
158 * @param array $boucles
159 *     AST du squelette
160 * @param Critere $crit
161 *     Paramètres du critère dans cette boucle
162 * @return
163 *     AST complété de la jointure correcte et des champs spéciaux
164**/
165function critere_contacts_auteurs_dist($idb, &$boucles, $crit) {
166        $boucle = &$boucles[$idb];
167
168        if ($boucle->id_table == 'auteurs') {
169                $cle = trouver_jointure_champ('id_contact', $boucle);
170
171                // Il faut déclarer la jointure explicite pour que les balises
172                // puissent chercher dans la table jointe.
173                // Ainsi #PRENOM sera retrouvé dans contacts, comme si
174                // on avait fait (AUTEURS contacts)
175                // cf. index_tables_en_pile() de public/references
176                $boucle->jointures_explicites = ltrim($boucle->jointures_explicites . ' contacts');
177
178                // On ajoute cependant en plus des champs calculés, potentiellement homonymes
179                $boucle->select[] = "$cle.nom AS nom_contact";
180                $boucle->select[] = "$cle.prenom AS prenom_contact";
181                $boucle->select[] = "$cle.civilite AS civilite_contact";
182
183        } elseif ($boucle->id_table == 'contacts') {
184                $cle = trouver_jointure_champ('id_auteur', $boucle);
185                $boucle->jointures_explicites = ltrim($boucle->jointures_explicites . ' auteurs');
186                $boucle->select[] = "$cle.nom AS nom_auteur";
187        } else {
188                // si le critère n'est pas sur une table articles ou contacts, c'est un problème.
189                return (array('zbug_critere_inconnu', array('critere' => $crit->op." ?")));
190        }
191}
192
193
194/**
195 * Calcul du critère `organisations_auteurs`
196 *
197 * Crée une jointure correcte entre auteurs et organisations et définit quelques
198 * champs spéciaux (nom_organisation, ...)
199 *
200 * @example
201 *     ```
202 *     <BOUCLE_(ORGANISATIONS){organisations_auteurs} />
203 *     <BOUCLE_(AUTEURS){organisations_auteurs} />
204 *     ```
205 *
206 * @critere
207 *
208 * @param string $idb
209 *     Identifiant de la boucle
210 * @param array $boucles
211 *     AST du squelette
212 * @param Critere $crit
213 *     Paramètres du critère dans cette boucle
214 * @return
215 *     AST complété de la jointure correcte et des champs spéciaux
216**/
217function critere_organisations_auteurs_dist($idb, &$boucles, $crit) {
218        $boucle = &$boucles[$idb];
219
220        if ($boucle->id_table == 'auteurs') {
221                $cle = trouver_jointure_champ('id_organisation', $boucle);
222
223                // cf critere contacts_auteurs pour explication
224                $boucle->jointures_explicites = ltrim($boucle->jointures_explicites . ' organisations');
225
226                // On ajoute cependant en plus des champs calculés, potentiellement homonymes
227                $boucle->select[] = "$cle.nom AS nom_organisation";
228
229        } elseif ($boucle->id_table == 'organisations') {
230                $cle = trouver_jointure_champ('id_auteur', $boucle);
231                $boucle->jointures_explicites = ltrim($boucle->jointures_explicites . ' auteurs');
232                $boucle->select[] = "$cle.nom AS nom_auteur";
233        } else {
234                // si le critère n'est pas sur une table articles ou contacts, c'est un problème.
235                return (array('zbug_critere_inconnu', array('critere' => $crit->op." ?")));
236        }
237}
238
239
240/**
241 * Calcul de la balise `#NOM_AUTEUR`
242 *
243 * Cette balise s'emploie dans une boucle `(CONTACTS){contacts_auteurs}`
244 * Elle nécessite le critère `contacts_auteurs` et retourne le champ
245 * `#NOM` de la table auteurs liée au contact.
246 *
247 * @balise
248 *
249 * @param Champ $p
250 *     Pile au niveau de la balise
251 * @return Champ
252 *     Pile complétée par le code à générer
253 */
254function balise_NOM_AUTEUR_dist($p) {
255        $p = rindex_pile($p, 'nom_auteur', 'contacts_auteurs');
256        if ($p->code == "''") {
257                $p = rindex_pile($p, 'nom_auteur', 'organisations_auteurs');
258        }
259        return $p;
260}
261
262
263/**
264 * Calcul de la balise `#PRENOM_CONTACT`
265 *
266 * Cette balise s'emploie dans une boucle `(AUTEURS){contacts_auteurs}`
267 * Elle nécessite le critère `contacts_auteurs` et retourne le champ
268 * `#PRENOM` de la table contacts liée à l'auteur.
269 *
270 * @note
271 *   Avec simplement le critère `contacts_auteurs`, la balise `#PRENOM`
272 *   fonctionne aussi (pour peu que la table articles n'ait pas ce champ
273 *   également).
274 *
275 * @balise
276 *
277 * @param Champ $p
278 *     Pile au niveau de la balise
279 * @return Champ
280 *     Pile complétée par le code à générer
281 */
282function balise_PRENOM_CONTACT_dist($p) {
283        return rindex_pile($p, 'prenom_contact', 'contacts_auteurs');
284}
285
286/**
287 * Calcul de la balise `#NOM_CONTACT`
288 *
289 * Cette balise s'emploie dans une boucle `(AUTEURS){contacts_auteurs}`
290 * Elle nécessite le critère `contacts_auteurs` et retourne le champ
291 * `#NOM` de la table contacts liée à l'auteur.
292 *
293 * @balise
294 *
295 * @param Champ $p
296 *     Pile au niveau de la balise
297 * @return Champ
298 *     Pile complétée par le code à générer
299 */
300function balise_NOM_CONTACT_dist($p) {
301        return rindex_pile($p, 'nom_contact', 'contacts_auteurs');
302}
303
304
305/**
306 * Calcul de la balise `#CIVILITE_CONTACT`
307 *
308 * Cette balise s'emploie dans une boucle `(AUTEURS){contacts_auteurs}`
309 * Elle nécessite le critère `contacts_auteurs` et retourne le champ
310 * `#CIVILITE` de la table contacts liée à l'auteur.
311 *
312 * @note
313 *   Avec simplement le critère `contacts_auteurs`, la balise `#CIVILITE`
314 *   fonctionne aussi (pour peu que la table articles n'ait pas ce champ
315 *   également).
316 *
317 * @balise
318 *
319 * @param Champ $p
320 *     Pile au niveau de la balise
321 * @return Champ
322 *     Pile complétée par le code à générer
323 */
324function balise_CIVILITE_CONTACT_dist($p) {
325        return rindex_pile($p, 'civilite_contact', 'contacts_auteurs');
326}
327
328/**
329 * Calcul de la balise `#NOM_ORGANISATION`
330 *
331 * Cette balise s'emploie dans une boucle `(AUTEURS){organisations_auteurs}`
332 * Elle nécessite le critère `organisations_auteurs` et retourne le champ
333 * `#NOM` de la table organisations liée à l'auteur.
334 *
335 * @balise
336 *
337 * @param Champ $p
338 *     Pile au niveau de la balise
339 * @return Champ
340 *     Pile complétée par le code à générer
341 */
342function balise_NOM_ORGANISATION_dist($p) {
343        return rindex_pile($p, 'nom_organisation', 'organisations_auteurs');
344}
345
346
347// Gestion des branches d'organisation
348// -----------------------------------
349
350
351/**
352 * Calcul de la balise `#IDS_ORGANISATION_BRANCHE`
353 *
354 * Cette balise retourne un tableau listant toutes les `id_organisation` d'une branche.
355 *
356 * L'identifiant de la branche (id_organisation) est pris dans la boucle
357 * la plus proche sinon dans l'environnement, sauf si l'on indique expressément
358 * les identifiants désirés
359 *
360 * @example
361 *   ```
362 *   #IDS_ORGANISATION_BRANCHE
363 *   #IDS_ORGANISATION_BRANCHE{4,10}
364 *   <BOUCLE_contacts(CONTACTS){id_organisation IN #IDS_ORGANISATION_BRANCHE}>
365 *   Pour ce dernier cas, préférer le critère branche_organisation :
366 *   <BOUCLE_contacts(CONTACTS){branche_organisation}>
367 *   ```
368 *
369 * @balise
370 *
371 * @param Champ $p
372 *     Pile au niveau de la balise
373 * @return Champ
374 *     Pile complétée par le code à générer
375 */
376function balise_IDS_ORGANISATION_BRANCHE_dist($p) {
377
378        // parcours de tous les identifiants recus en parametre
379        $n = 0;
380        $ids = array();
381        while ($id_org = interprete_argument_balise(++$n, $p)) {
382                if ($id_org = trim(trim($id_org), "'")) { // vire les guillements pour accepter soit un terme soit un nombre
383                        $ids = array_merge($ids, array($id_org)); // ... les merge avec id
384                }
385        }
386
387        // pas d'identifiant, on prend la boucle la plus proche
388        if (!$ids) {
389                $ids = champ_sql('id_organisation', $p);
390                $p->code = "explode(',', calcul_organisation_branche_in($ids))"; // 200
391        } else {
392                $p->code = "explode(',', calcul_organisation_branche_in(" . var_export($ids, true) . "))"; // 200
393        }
394
395        return $p;
396}
397
398
399
400/**
401 * Calcul d'une branche d'organisation
402 *
403 * Liste des `id_organisation` contenues dans une organisation donnée
404 *
405 * @param string|int|array $id
406 *   Identifiant(s) d'organisation(s) dont on veut les branches
407 * @return string
408 *   Liste des identifiants d'organisation de ou des branches, séparés par des virgules.
409 */
410function calcul_organisation_branche_in($id) {
411        static $b = array();
412
413        // normaliser $id qui a pu arriver comme un array, comme un entier, ou comme une chaine NN,NN,NN
414        if (!is_array($id)) $id = explode(',', $id);
415        $id = join(',', array_map('intval', $id));
416        if (isset($b[$id]))
417                return $b[$id];
418
419        // Notre branche commence par l'organisation de depart
420        $branche = $r = $id;
421
422        // On ajoute une generation (les filles de la generation precedente)
423        // jusqu'a epuisement
424        while ($filles = sql_allfetsel(
425                                        'id_organisation',
426                                        'spip_organisations',
427                                        sql_in('id_parent', $r)." AND ". sql_in('id_organisation', $r, 'NOT')
428        )) {
429                $r = join(',', array_map('array_shift', $filles));
430                $branche .= ',' . $r;
431        }
432
433        # securite pour ne pas plomber la conso memoire sur les sites prolifiques
434        if (strlen($branche) < 10000)
435                $b[$id] = $branche;
436        return $branche;
437}
438
439
440
441/**
442 * Compile le critère `branche_organisation`. Il sélectionne dans une
443 * boucle les éléments appartenant à une branche d'une organisation.
444 *
445 * Calcule une branche d'une organisation et conditionne la boucle avec.
446 * Cherche l'identifiant de l'organisation en premier paramètre du critère
447 * `{branche_organisation XX}` sinon dans les boucles parentes ou par jointure.
448 *
449 * @example
450 *   ```
451 *   <BOUCLE_contacts(CONTACTS){branche_organisation}>
452 *   ```
453 *
454 * @internal
455 *     Copie quasi identique de `critere_branche_dist()`
456 *
457 * @critere
458 *
459 * @param string $idb
460 *     Identifiant de la boucle
461 * @param array $boucles
462 *     AST du squelette
463 * @param Critere $crit
464 *     Paramètres du critère dans cette boucle
465 * @return void
466**/
467function critere_branche_organisation_dist($idb, &$boucles, $crit) {
468
469        $not = $crit->not;
470        $boucle = &$boucles[$idb];
471        // prendre en priorite un identifiant en parametre {branche_organisation XX}
472        if (isset($crit->param[0])) {
473                $arg = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
474        }
475        // sinon on le prend chez une boucle parente
476        else {
477                $arg = kwote(calculer_argument_precedent($idb, 'id_organisation', $boucles));
478        }
479
480        // Trouver une jointure
481        $champ = "id_organisation";
482        $desc = $boucle->show;
483        //Seulement si necessaire
484        if (!array_key_exists($champ, $desc['field'])){
485                $cle = trouver_jointure_champ($champ, $boucle);
486                $trouver_table = charger_fonction("trouver_table", "base");
487                $desc = $trouver_table($boucle->from[$cle]);
488                if (count(trouver_champs_decomposes($champ, $desc)) > 1){
489                        $decompose = decompose_champ_id_objet($champ);
490                        $champ = array_shift($decompose);
491                        $boucle->where[] = array("'='", _q($cle.".".reset($decompose)), '"'.sql_quote(end($decompose)).'"');
492                }
493        }
494        else $cle = $boucle->id_table;
495
496        $c = "sql_in('$cle".".$champ', calcul_organisation_branche_in($arg)"
497             .($not ? ", 'NOT'" : '').")";
498        $boucle->where[] = !$crit->cond ? $c :
499                ("($arg ? $c : ".($not ? "'0=1'" : "'1=1'").')');
500}
Note: See TracBrowser for help on using the repository browser.