source: spip-zone/_plugins_/compositions/trunk/compositions_fonctions.php @ 82878

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

Améliorer la présentation visuelle de la page ?exec=compositions en spip 3.

File size: 15.1 KB
Line 
1<?php
2/**
3 * Plugin Compositions
4 * (c) 2007-2013 Cedric Morin
5 * Distribue sous licence GPL
6 *
7 * @package SPIP\Compositions\Fonctions
8 */
9
10if (!defined("_ECRIRE_INC_VERSION")) return;
11
12define('_COMPOSITIONS_MATCH','-([^0-9][^.]*)');
13$GLOBALS['marqueur_skel'] = (isset($GLOBALS['marqueur_skel'])?$GLOBALS['marqueur_skel']:'').':composition';
14
15/**
16 * Lister les objets actives par configuration
17 *
18 * @return array
19 */
20function compositions_objets_actives(){
21        static $config=null;
22        if (is_null($config)){
23                // lister les objets dont on a active la composition dans la configuration
24                $config = isset($GLOBALS['meta']['compositions']) ? unserialize($GLOBALS['meta']['compositions']) : array();
25                $config = (isset($config['objets'])?$config['objets']:array('spip_articles','spip_rubriques'));
26                $config = array_map('objet_type',$config);
27        }
28        return $config;
29}
30
31/**
32 * Retrouver le nom du dossier ou sont stockees les compositions
33 * reglage par defaut, ou valeur personalisee via cfg
34 *
35 * @return string
36 */
37function compositions_chemin(){
38        $config_chemin = 'compositions/';
39        if (defined('_DIR_PLUGIN_Z') OR defined('_DIR_PLUGIN_ZCORE'))
40                $config_chemin = (isset($GLOBALS['z_blocs'])?reset($GLOBALS['z_blocs']):'contenu').'/';
41
42        elseif (isset($GLOBALS['meta']['compositions'])){
43                $config = unserialize($GLOBALS['meta']['compositions']);
44                if (isset ($config['chemin_compositions'])){
45                        $config_chemin = rtrim($config['chemin_compositions'],'/').'/';
46                }
47        }
48
49        return $config_chemin;
50}
51
52/**
53 * Tester si la stylisation auto est activee
54 * @return string
55 */
56function compositions_styliser_auto(){
57        $config_styliser = true;
58        if (defined('_DIR_PLUGIN_Z') OR defined('_DIR_PLUGIN_ZCORE')){
59                $config_styliser = false; // Z s'occupe de styliser les compositions
60        }
61        elseif (isset($GLOBALS['meta']['compositions'])){
62                $config = unserialize($GLOBALS['meta']['compositions']);
63                $config_styliser = $config['styliser_auto'] != 'non';
64        }
65        return $config_styliser?' ':'';
66}
67
68/**
69 * Lister les compositions disponibles : toutes ou pour un type donne
70 * Si informer est a false, on ne charge pas les infos du xml
71 *
72 * @param string $type
73 * @param bool $informer
74 * @return array
75 */
76function compositions_lister_disponibles($type, $informer=true){
77        include_spip('inc/compositions');
78        $type_match = "";
79        if (strlen($type)){
80                $type = objet_type($type); // securite
81                $type_match = $type;
82        }
83        else {
84                $type_match = "[a-z0-9]+";
85        }
86
87        // rechercher les skel du type article-truc.html
88        // truc ne doit pas commencer par un chiffre pour eviter de confondre avec article-12.html
89        $match = "($type_match)("._COMPOSITIONS_MATCH.")?[.]html$";
90
91        // lister les compositions disponibles
92        $liste = find_all_in_path(compositions_chemin(),$match);
93        $res = array();
94        if (count($liste)){
95                foreach($liste as $s) {
96                        $base = preg_replace(',[.]html$,i','',$s);
97                        if (preg_match(",$match,ims",basename($s),$regs)
98                          AND ($composition = !$informer
99                                OR $composition = compositions_charger_infos($base)))
100                                $res[$regs[1]][$regs[3]] = $composition;
101                        // retenir les skels qui ont un xml associe
102                }
103        }
104        // Pipeline compositions_lister_disponibles
105        $res = pipeline('compositions_lister_disponibles',array(
106                'args'=>array('type' => $type,'informer' => $informer),
107                'data'=> $res
108                )
109        );
110        return $res;
111}
112
113/**
114 * Liste les id d'un type donne utilisant une composition donnee
115 *
116 * @param string $type
117 * @param string $composition
118 * @return array
119 */
120function compositions_lister_utilisations($type,$composition){
121        $table_sql = table_objet_sql($type);
122        if (!in_array($table_sql, sql_alltable())) return;
123        $_id_table_objet = id_table_objet($type);
124        return sql_allfetsel("$_id_table_objet as id,titre", $table_sql, "composition=".sql_quote($composition));
125}
126
127/**
128 * Selectionner le fond en fonction du type et de la composition
129 * en prenant en compte la configuration pour le chemin
130 * et le fait que la composition a pu etre supprimee
131 *
132 * @param string $composition
133 * @param string $type
134 * @param string $defaut
135 * @param string $ext
136 * @param bool $fullpath
137 * @param string $vide
138 * @return string
139 */
140function compositions_selectionner($composition,$type,$defaut="",$ext="html",$fullpath = false, $vide="composition-vide"){
141        if ($type=='syndic') $type='site'; //grml
142        $fond = compositions_chemin() . $type;
143
144        // regarder si compositions/article-xxx est disponible
145        if (strlen($composition)
146                AND $f = find_in_path("$fond-$composition.$ext"))
147                return $fullpath ? $f : $fond . "-$composition";
148        else
149                // sinon regarder si compositions/article-defaut est disponible
150                if (strlen($defaut)
151                        AND $f = find_in_path("$fond-$defaut.$ext"))
152                        return $fullpath ? $f : $fond . "-$defaut";
153
154        // se rabattre sur compositions/article si disponible
155        if ($f = find_in_path("$fond.$ext"))
156                return $fullpath ? $f : $fond;
157
158        // sinon une composition vide pour ne pas generer d'erreur
159        if ($vide AND $f = find_in_path("$vide.$ext"))
160                return $fullpath ? $f : $vide;
161
162        // rien mais ca fera une erreur dans le squelette si appele en filtre
163        return '';
164}
165
166/**
167 * Decrire une composition pour un objet
168 * @param string $type
169 * @param string $composition
170 * @return array|bool|string
171 */
172function compositions_decrire($type, $composition){
173        static $compositions = array();
174        if (!function_exists('compositions_charger_infos'))
175                include_spip('inc/compositions');
176        if ($type=='syndic') $type='site'; //grml
177        if (isset($compositions[$type][$composition]))
178                return $compositions[$type][$composition];
179        $ext = "html";
180        $fond = compositions_chemin() . $type;
181        if (strlen($composition)
182                AND $f = find_in_path("$fond-$composition.$ext")
183                AND $desc = compositions_charger_infos($f))
184                return $compositions[$type][$composition] = $desc;
185        return $compositions[$type][$composition] = false;
186}
187
188/**
189 * Un filtre a utiliser sur [(#COMPOSITION|composition_class{#ENV{type}})]
190 * pour poser des classes generiques sur le <body>
191 * si une balise <class>toto</class> est definie dans la composition c'est elle qui est appliquee
192 * sinon on pose simplement le nom de la composition
193 *
194 * @param string $composition
195 * @param string $type
196 * @return string
197 */
198function composition_class($composition,$type){
199        if ($desc = compositions_decrire($type, $composition)
200                AND isset($desc['class'])
201                AND strlen($desc['class']))
202                return $desc['class'];
203        return $composition;
204}
205
206/**
207 * Liste les types d'objets qui ont une composition ET sont autorises par la configuration
208 * utilise la valeur en cache meta sauf si demande de recalcul
209 * ou pas encore definie
210 *
211 * @staticvar array $liste
212 * @return array
213 */
214function compositions_types(){
215        static $liste = null;
216        if (is_null($liste)) {
217                if (_VAR_MODE OR !isset($GLOBALS['meta']['compositions_types'])){
218                        include_spip('inc/compositions');
219                        compositions_cacher();
220                }
221                $liste = explode(',',$GLOBALS['meta']['compositions_types']);
222        }
223        return $liste;
224}
225
226/**
227 * Renvoie les parametres necessaires pour utiliser l'heritage de composition de façon generique
228 * recupere les donnes du pipeline compositions_declarer_heritage.
229 * Si $type n'est pas precise, on renvoie simplement le tableau des objets pouvant heriter.
230 *
231 * @param string $type
232 * @staticvar array $heritages
233 * @return array
234 */
235function compositions_recuperer_heritage($type=NULL){
236        static $heritages = NULL;
237        if (is_null($heritages)) // recuperer les heritages declares via le pipeline compositions_declarer_heritage
238                $heritages = pipeline('compositions_declarer_heritage', array());
239
240        if (is_null($type))
241                return $heritages;
242
243        if (array_key_exists($type, $heritages)) {
244                $type_parent = $heritages[$type];
245                $table_parent =  table_objet_sql($type_parent);
246                $nom_id_parent = ($type==$type_parent) ? 'id_parent' : id_table_objet($type_parent); // Recursivite pour les rubriques, nom de l'identifiant du parent dans la table enfant
247                $nom_id_table_parent = id_table_objet($type_parent); // Nom de l'identifiant du parent dans la table parent
248
249                // verifier que table et champs existent...
250                $trouver_table = charger_fonction('trouver_table', 'base');
251                if (!$type_parent
252                        OR !$desc = $trouver_table($table_parent)
253                        OR !isset($desc['field']['composition'])
254                        OR !isset($desc['field'][$nom_id_parent]))
255                        return '';
256
257                return array(
258                        'type_parent' => $type_parent,
259                        'table_parent' => $table_parent,
260                        'nom_id_parent' => $nom_id_parent,
261                        'nom_id_table_parent' => $nom_id_table_parent
262                );
263        }
264        return array();
265}
266
267/**
268 * Renvoie la composition qui s'applique a un objet
269 * en tenant compte, le cas echeant, de la composition heritee
270 * si etoile=true on renvoi directment le champ sql
271 *
272 * @param string $type
273 * @param integer $id
274 * @param string $serveur
275 * @param bool $etoile
276 * @return string
277 */
278function compositions_determiner($type, $id, $serveur='', $etoile = false){
279        static $composition = array();
280        $id = intval($id);
281
282        if (isset($composition[$etoile][$serveur][$type][$id]))
283                return $composition[$etoile][$serveur][$type][$id];
284
285        include_spip('base/abstract_sql');
286        $table = table_objet($type);
287        $table_sql = table_objet_sql($type);
288        $_id_table = id_table_objet($type);
289
290        $retour = '';
291
292        $trouver_table = charger_fonction('trouver_table', 'base');
293        $desc = $trouver_table($table,$serveur);
294        if (isset($desc['field']['composition']) AND $id){
295                $select = "composition";
296
297        $heritage = compositions_recuperer_heritage($type);
298        if (isset($desc['field'][$heritage['nom_id_parent']]))
299                $select .= ', '.$heritage['nom_id_parent'].' as id_parent';
300
301        $row = sql_fetsel($select, $table_sql, "$_id_table=".intval($id), '', '', '', '', $serveur);
302        if ($row['composition'] != '')
303                $retour = $row['composition'];
304        elseif (!$etoile
305          AND isset($row['id_parent'])
306          AND $row['id_parent'])
307                $retour = compositions_heriter($type, $id, $row['id_parent'], $serveur);
308        }
309        return $composition[$etoile][$serveur][$type][$id] = (($retour == '-') ? '' : $retour);
310}
311
312/**
313 * Renvoie la composition heritee par un objet selon son identifiant.
314 * Optionnellement, on peut lui transmettre directement l'id du parent s'il a ate calcule.
315 *
316 * @param string $type
317 * @param integer $id
318 * @param integer $id_parent
319 * @param string $serveur
320 * @return string
321 */
322function compositions_heriter($type, $id, $id_parent=NULL, $serveur=''){
323        if ($type=='syndic') $type='site'; //grml
324        if (intval($id) < 1) return '';
325        static $infos = null;
326        $compo_parent = '';
327
328        $heritage = compositions_recuperer_heritage($type);
329
330        /* Si aucun héritage n'a été défini pour le type d'objet, ce
331        * n'est pas la peine d'aller plus loin. */
332        if(count($heritage) == 0)
333                return '';
334
335        $type_parent = $heritage['type_parent'];
336        $table_parent = $heritage['table_parent'];
337        $nom_id_parent = $heritage['nom_id_parent'];
338        $nom_id_table_parent = $heritage['nom_id_table_parent'];
339
340        if (is_null($id_parent))
341                $id_parent = sql_getfetsel($nom_id_parent, table_objet_sql($type), id_table_objet($type).'='.intval($id));
342
343        $heritages = compositions_recuperer_heritage();
344
345        do {
346                $select = 'composition';
347                if ($heritages[$type_parent]==$type_parent) // S'il y a recursivite sur le parent
348                        $select .= ', id_parent';
349                $row = sql_fetsel($select, $table_parent, $nom_id_table_parent.'='.intval($id_parent),'','','','',$serveur);
350                if (strlen($row['composition']) AND $row['composition']!='-')
351                        $compo_parent = $row['composition'];
352                elseif (strlen($row['composition'])==0 AND isset($heritages[$type_parent])) // Si le parent peut heriter, il faut verifier s'il y a heritage
353                        $compo_parent = compositions_determiner($type_parent, $id_parent, $serveur='');
354
355                if (strlen($compo_parent) AND is_null($infos))
356                        $infos = compositions_lister_disponibles('');
357
358        }
359        while ($id_parent = $row['id_parent']
360                AND
361                (!strlen($compo_parent) OR !isset($infos[$type_parent][$compo_parent]['branche'][$type])));
362
363        if (strlen($compo_parent) AND isset($infos[$type_parent][$compo_parent]['branche'][$type]))
364                return $infos[$type_parent][$compo_parent]['branche'][$type];
365
366        return '';
367}
368
369/**
370 * #COMPOSITION
371 * Renvoie la composition s'appliquant a un objet
372 * en tenant compte, le cas echeant, de l'heritage.
373 *
374 * Sans precision, l'objet et son identifiant sont pris
375 * dans la boucle en cours, mais l'on peut specifier notre recherche
376 * en passant objet et id_objet en argument de la balise :
377 * #COMPOSITION{article, 8}
378 *
379 * #COMPOSITION* renvoie toujours le champs brut, sans tenir compte de l'heritage
380 *
381 * @param array $p      AST au niveau de la balise
382 * @return array        AST->code modifie pour calculer le nom de la composition
383 */
384function balise_COMPOSITION_dist($p) {
385        $_composition = "";
386        if ($_objet = interprete_argument_balise(1, $p)) {
387                $_id_objet = interprete_argument_balise(2, $p);
388        } else {
389                $_composition = champ_sql('composition',$p);
390                $_id_objet = champ_sql($p->boucles[$p->id_boucle]->primary, $p);
391                $_objet = "objet_type('" . $p->boucles[$p->id_boucle]->id_table . "')";
392        }
393        // si on veut le champ brut, et qu'on l'a sous la main, inutile d'invoquer toute la machinerie
394        if ($_composition AND $p->etoile)
395                $p->code = $_composition;
396        else {
397                $connect = $p->boucles[$p->id_boucle]->sql_serveur;
398                $p->code = "compositions_determiner($_objet, $_id_objet, '$connect', ".($p->etoile?'true':'false').")";
399                // ne declencher l'usine a gaz que si composition est vide ...
400                if ($_composition)
401                        $p->code = "((\$zc=$_composition)?(\$zc=='-'?'':\$zc):".$p->code.")";
402        }
403        return $p;
404}
405
406/**
407 * Indique si la composition d'un objet est verrouillee ou non,
408 * auquel cas, seul le webmaster peut la modifier
409 *
410 * @param string $type
411 * @param integer $id
412 * @param string $serveur
413 * @return string
414 */
415function compositions_verrouiller($type, $id, $serveur=''){
416        $config = unserialize($GLOBALS['meta']['compositions']);
417        if (isset($config['tout_verrouiller']) AND $config['tout_verrouiller'] == 'oui')
418                return true;
419
420        include_spip('base/abstract_sql');
421        $table = table_objet($type);
422        $table_sql = table_objet_sql($type);
423        $_id_table = id_table_objet($type);
424
425        $trouver_table = charger_fonction('trouver_table', 'base');
426        $desc = $trouver_table($table,$serveur);
427        if (isset($desc['field']['composition_lock']) AND $id){
428                $lock = sql_getfetsel('composition_lock', $table_sql, "$_id_table=".intval($id), '', '', '', '', $serveur);
429                if ($lock)
430                        return true;
431                elseif (isset($desc['field']['id_rubrique'])) {
432                        $id_rubrique = sql_getfetsel('id_rubrique', $table_sql, "$_id_table=".intval($id), '', '', '', '', $serveur);
433                        return compositions_verrou_branche($id_rubrique, $serveur);
434                }
435                else
436                        return false;
437        }
438        else return false;
439}
440
441/**
442 * Indique si les objets d'une branche sont verrouilles
443 * @param integer $id_rubrique
444 * @param string $serveur
445 * @return string
446 */
447function compositions_verrou_branche($id_rubrique, $serveur=''){
448
449        if (intval($id_rubrique) < 1) return false;
450        if($infos_rubrique = sql_fetsel(array('id_parent','composition_branche_lock'),'spip_rubriques','id_rubrique='.intval($id_rubrique),'','','','',$serveur)) {
451                if ($infos_rubrique['composition_branche_lock'])
452                        return true;
453                else
454                        return compositions_verrou_branche($infos_rubrique['id_parent'],$serveur);
455        }
456        return '';
457}
458?>
Note: See TracBrowser for help on using the repository browser.