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

Last change on this file since 75246 was 75246, checked in by marcimat@…, 8 years ago

simplification du phpdoc

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