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