[SPIP] ~maj v3.0.14-->v3.0.17
[ptitvelo/web/www.git] / www / ecrire / base / objets.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2014 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * Fonctions relatives aux objets éditoriaux et SQL
15 *
16 * @package SPIP\SQL\Tables
17 **/
18
19 if (!defined('_ECRIRE_INC_VERSION')) return;
20
21 /**
22 * Merge dans un tableau une de ses clés avec une valeur
23 *
24 * @param array $table
25 * Tableau dont on veut compléter une clé
26 * @param string $index
27 * Clé du tableau que l'on souhaite compléter
28 * @param array $valeur
29 * Sous tableau à merger dans la clé.
30 * @return void
31 **/
32 function array_set_merge(&$table,$index,$valeur){
33 if (!isset($table[$index]))
34 $table[$index] = $valeur;
35 else
36 $table[$index] = array_merge($table[$index],$valeur);
37 }
38
39 /**
40 * Lister les infos de toutes les tables sql declarées
41 *
42 * Si un argument est fourni, on ne renvoie que les infos de cette table.
43 * Elle est auto-declarée si inconnue jusqu'alors.
44 *
45 * @api
46 * @param string $table_sql
47 * table_sql demandee explicitement
48 * @param array $desc
49 * description connue de la table sql demandee
50 * @return array|bool
51 */
52 function lister_tables_objets_sql($table_sql=null, $desc=array()){
53 static $deja_la = false;
54 static $infos_tables = null;
55 static $md5 = null;
56 static $plugin_hash = null;
57 // prealablement recuperer les tables_principales
58 if (is_null($infos_tables)
59 OR $plugin_hash!==_PLUGINS_HASH){
60 // pas de reentrance (cas base/serial)
61 if ($deja_la) {
62 spip_log ("Re-entrance anormale sur lister_tables_objets_sql :"
63 . var_export(debug_backtrace(),true),_LOG_CRITIQUE);
64 return ($table_sql==="::md5"?$md5:array());
65 }
66 $deja_la = true;
67 $plugin_hash = _PLUGINS_HASH; // avant de lancer les pipelines
68
69 // recuperer les declarations explicites ancienne mode
70 // qui servent a completer declarer_tables_objets_sql
71 base_serial($GLOBALS['tables_principales']);
72 base_auxiliaires($GLOBALS['tables_auxiliaires']);
73 $infos_tables = array(
74 'spip_articles'=> array(
75 'page'=>'article',
76 'texte_retour' => 'icone_retour_article',
77 'texte_modifier' => 'icone_modifier_article',
78 'texte_creer' => 'icone_ecrire_article',
79 'texte_objets' => 'public:articles',
80 'texte_objet' => 'public:article',
81 'texte_signale_edition' => 'texte_travail_article',
82 'info_aucun_objet'=> 'info_aucun_article',
83 'info_1_objet' => 'info_1_article',
84 'info_nb_objets' => 'info_nb_articles',
85 'texte_logo_objet' => 'logo_article',
86 'texte_langue_objet' => 'titre_langue_article',
87 'texte_definir_comme_traduction_objet' => 'trad_lier',
88 'titre' => 'titre, lang',
89 'date' => 'date',
90 'principale' => 'oui',
91 'champs_editables' => array('surtitre', 'titre', 'soustitre', 'descriptif','nom_site', 'url_site', 'chapo', 'texte', 'ps','virtuel'),
92 'champs_versionnes' => array('id_rubrique', 'surtitre', 'titre', 'soustitre', 'jointure_auteurs', 'descriptif', 'nom_site', 'url_site', 'chapo', 'texte', 'ps'),
93 'field' => array(
94 "id_article" => "bigint(21) NOT NULL",
95 "surtitre" => "text DEFAULT '' NOT NULL",
96 "titre" => "text DEFAULT '' NOT NULL",
97 "soustitre" => "text DEFAULT '' NOT NULL",
98 "id_rubrique" => "bigint(21) DEFAULT '0' NOT NULL",
99 "descriptif" => "text DEFAULT '' NOT NULL",
100 "chapo" => "mediumtext DEFAULT '' NOT NULL",
101 "texte" => "longtext DEFAULT '' NOT NULL",
102 "ps" => "mediumtext DEFAULT '' NOT NULL",
103 "date" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
104 "statut" => "varchar(10) DEFAULT '0' NOT NULL",
105 "id_secteur" => "bigint(21) DEFAULT '0' NOT NULL",
106 "maj" => "TIMESTAMP",
107 "export" => "VARCHAR(10) DEFAULT 'oui'",
108 "date_redac" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
109 "visites" => "integer DEFAULT '0' NOT NULL",
110 "referers" => "integer DEFAULT '0' NOT NULL",
111 "popularite" => "DOUBLE DEFAULT '0' NOT NULL",
112 "accepter_forum" => "CHAR(3) DEFAULT '' NOT NULL",
113 "date_modif" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
114 "lang" => "VARCHAR(10) DEFAULT '' NOT NULL",
115 "langue_choisie" => "VARCHAR(3) DEFAULT 'non'",
116 "id_trad" => "bigint(21) DEFAULT '0' NOT NULL",
117 "nom_site" => "tinytext DEFAULT '' NOT NULL",
118 "url_site" => "VARCHAR(255) DEFAULT '' NOT NULL",
119 "virtuel" => "VARCHAR(255) DEFAULT '' NOT NULL",
120 ),
121 'key' => array(
122 "PRIMARY KEY" => "id_article",
123 "KEY id_rubrique" => "id_rubrique",
124 "KEY id_secteur" => "id_secteur",
125 "KEY id_trad" => "id_trad",
126 "KEY lang" => "lang",
127 "KEY statut" => "statut, date",
128 ),
129 'join' => array(
130 "id_article"=>"id_article",
131 "id_rubrique"=>"id_rubrique"
132 ),
133 'rechercher_champs' => array(
134 'surtitre' => 5, 'titre' => 8, 'soustitre' => 5, 'chapo' => 3,
135 'texte' => 1, 'ps' => 1, 'nom_site' => 1, 'url_site' => 1,
136 'descriptif' => 4
137 ),
138 'rechercher_jointures' => array(
139 'auteur' => array('nom' => 10),
140 ),
141 'statut'=> array(
142 array(
143 'champ' => 'statut',
144 'publie' => 'publie',
145 'previsu' => 'publie,prop,prepa/auteur',
146 'post_date' => 'date',
147 'exception' => 'statut'
148 )
149 ),
150 'statut_titres' => array(
151 'prepa'=>'info_article_redaction',
152 'prop'=>'info_article_propose',
153 'publie'=>'info_article_publie',
154 'refuse'=>'info_article_refuse',
155 'poubelle'=>'info_article_supprime'
156 ),
157 'statut_textes_instituer' => array(
158 'prepa' => 'texte_statut_en_cours_redaction',
159 'prop' => 'texte_statut_propose_evaluation',
160 'publie' => 'texte_statut_publie',
161 'refuse' => 'texte_statut_refuse',
162 'poubelle' => 'texte_statut_poubelle',
163 ),
164 'texte_changer_statut' => 'texte_article_statut',
165 'aide_changer_statut' => 'artstatut',
166 'tables_jointures' => array(
167 'profondeur' => 'rubriques',
168 #'id_auteur' => 'auteurs_liens' // declaration generique plus bas
169 ),
170 ),
171 'spip_auteurs' => array(
172 'page'=>'auteur',
173 'texte_retour' => 'icone_retour',
174 'texte_ajouter' => 'titre_ajouter_un_auteur',
175 'texte_modifier' => 'admin_modifier_auteur',
176 'texte_objets' => 'icone_auteurs',
177 'texte_objet' => 'public:auteur',
178 'info_aucun_objet'=> 'info_aucun_auteur',
179 'info_1_objet' => 'info_1_auteur',
180 'info_nb_objets' => 'info_nb_auteurs',
181 'texte_logo_objet' => 'logo_auteur',
182 'texte_creer_associer' => 'creer_et_associer_un_auteur',
183 'titre' => "nom AS titre, '' AS lang",
184 'date' => 'date',
185 'principale' => 'oui',
186 'champs_editables' => array('nom','email','bio','nom_site','url_site','imessage','pgp'),
187 'champs_versionnes' => array('nom', 'bio', 'email', 'nom_site', 'url_site', 'login'),
188 'field' => array(
189 "id_auteur" => "bigint(21) NOT NULL",
190 "nom" => "text DEFAULT '' NOT NULL",
191 "bio" => "text DEFAULT '' NOT NULL",
192 "email" => "tinytext DEFAULT '' NOT NULL",
193 "nom_site" => "tinytext DEFAULT '' NOT NULL",
194 "url_site" => "text DEFAULT '' NOT NULL",
195 "login" => "VARCHAR(255) BINARY",
196 "pass" => "tinytext DEFAULT '' NOT NULL",
197 "low_sec" => "tinytext DEFAULT '' NOT NULL",
198 "statut" => "varchar(255) DEFAULT '0' NOT NULL",
199 "webmestre" => "varchar(3) DEFAULT 'non' NOT NULL",
200 "maj" => "TIMESTAMP",
201 "pgp" => "TEXT DEFAULT '' NOT NULL",
202 "htpass" => "tinytext DEFAULT '' NOT NULL",
203 "en_ligne" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
204 "alea_actuel" => "tinytext",
205 "alea_futur" => "tinytext",
206 "prefs" => "tinytext",
207 "cookie_oubli" => "tinytext",
208 "source" => "VARCHAR(10) DEFAULT 'spip' NOT NULL",
209 "lang" => "VARCHAR(10) DEFAULT '' NOT NULL"
210 ),
211 'key' => array(
212 "PRIMARY KEY" => "id_auteur",
213 "KEY login" => "login",
214 "KEY statut" => "statut",
215 "KEY en_ligne" => "en_ligne",
216 ),
217 'join' => array(
218 "id_auteur"=>"id_auteur",
219 "login"=>"login"
220 ),
221 'rechercher_champs' => array(
222 'nom' => 5, 'bio' => 1, 'email' => 1, 'nom_site' => 1, 'url_site' => 1, 'login' => 1
223 ),
224 // 2 conditions pour les auteurs : statut!=poubelle,
225 // et avoir des articles publies
226 'statut'=> array(
227 array(
228 'champ' => 'statut',
229 'publie' => '!5poubelle',
230 'previsu' => '!5poubelle',
231 'exception' => 'statut'
232 ),
233 array(
234 'champ' => array(
235 array('spip_auteurs_liens', 'id_auteur'),
236 array(
237 'spip_articles',
238 array('id_objet','id_article','objet','article')
239 ),
240 'statut'
241 ),
242 'publie' => 'publie',
243 'previsu' => '!',
244 'post_date' => 'date',
245 'exception' => array('statut','lien','tout')
246 ),
247 ),
248 'statut_images' => array(
249 'auteur-6forum-16.png',
250 '0minirezo'=>'auteur-0minirezo-16.png',
251 '1comite'=>'auteur-1comite-16.png',
252 '6forum'=>'auteur-6forum-16.png',
253 '5poubelle'=>'auteur-5poubelle-16.png',
254 'nouveau'=>''
255 ),
256 'statut_titres' => array(
257 'titre_image_visiteur',
258 '0minirezo'=>'titre_image_administrateur',
259 '1comite'=>'titre_image_redacteur_02',
260 '6forum'=>'titre_image_visiteur',
261 '5poubelle'=>'titre_image_auteur_supprime',
262 ),
263 'tables_jointures' => array(
264 #'auteurs_liens' // declaration generique plus bas
265 ),
266 ),
267 'spip_rubriques' => array(
268 'page'=>'rubrique',
269 'url_voir' => 'rubrique',
270 'url_edit' => 'rubrique_edit',
271 'texte_retour' => 'icone_retour',
272 'texte_objets' => 'public:rubriques',
273 'texte_objet' => 'public:rubrique',
274 'texte_modifier' => 'icone_modifier_rubrique',
275 'texte_creer' => 'icone_creer_rubrique',
276 'texte_ajouter' => 'titre_ajouter_une_rubrique',
277 'texte_creer_associer' => 'creer_et_associer_une_rubrique',
278 'info_aucun_objet'=> 'info_aucun_rubrique',
279 'info_1_objet' => 'info_1_rubrique',
280 'info_nb_objets' => 'info_nb_rubriques',
281 'texte_logo_objet' => 'logo_rubrique',
282 'texte_langue_objet' => 'titre_langue_rubrique',
283 'titre'=>'titre, lang',
284 'date' => 'date',
285 'principale' => 'oui',
286 'champs_editables' => array('titre', 'texte', 'descriptif', 'extra'),
287 'champs_versionnes' => array('titre', 'descriptif', 'texte'),
288 'field' => array(
289 "id_rubrique" => "bigint(21) NOT NULL",
290 "id_parent" => "bigint(21) DEFAULT '0' NOT NULL",
291 "titre" => "text DEFAULT '' NOT NULL",
292 "descriptif" => "text DEFAULT '' NOT NULL",
293 "texte" => "longtext DEFAULT '' NOT NULL",
294 "id_secteur" => "bigint(21) DEFAULT '0' NOT NULL",
295 "maj" => "TIMESTAMP",
296 "statut" => "varchar(10) DEFAULT '0' NOT NULL",
297 "date" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
298 "lang" => "VARCHAR(10) DEFAULT '' NOT NULL",
299 "langue_choisie" => "VARCHAR(3) DEFAULT 'non'",
300 "statut_tmp" => "varchar(10) DEFAULT '0' NOT NULL",
301 "date_tmp" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
302 "profondeur" => "smallint(5) DEFAULT '0' NOT NULL"
303 ),
304 'key' => array(
305 "PRIMARY KEY" => "id_rubrique",
306 "KEY lang" => "lang",
307 "KEY id_parent" => "id_parent",
308 ),
309 'rechercher_champs' => array(
310 'titre' => 8, 'descriptif' => 5, 'texte' => 1
311 ),
312 'statut' => array(
313 array(
314 'champ' => 'statut',
315 'publie' => 'publie',
316 'previsu' => '!',
317 'exception' => array('statut','tout')
318 ),
319 ),
320 'tables_jointures' => array(
321 #'id_auteur' => 'auteurs_liens' // declaration generique plus bas
322 ),
323 ),
324 // toutes les tables ont le droit a une jointure sur les auteurs
325 array('tables_jointures'=>array('id_auteur'=>'auteurs_liens'))
326 );
327
328 // avant d'appeller les pipeline qui peuvent generer une reentrance a l'install
329 // initialiser la signature
330 $md5 = md5(serialize($infos_tables));
331
332 $GLOBALS['tables_principales'] = pipeline('declarer_tables_principales',$GLOBALS['tables_principales']);
333 $GLOBALS['tables_auxiliaires'] = pipeline('declarer_tables_auxiliaires',$GLOBALS['tables_auxiliaires']);
334 $infos_tables = pipeline('declarer_tables_objets_sql',$infos_tables);
335
336 // completer les informations manquantes ou implicites
337 $all = array();
338 foreach(array_keys($infos_tables) as $t) {
339 // les cles numeriques servent a declarer
340 // les proprietes applicables a tous les objets
341 // on les mets de cote
342 if (is_numeric($t)) {
343 $all = array_merge_recursive($all,$infos_tables[$t]);
344 unset($infos_tables[$t]);
345 }
346 else
347 $infos_tables[$t] = renseigner_table_objet_sql($t,$infos_tables[$t]);
348 }
349
350 // repercuter les proprietes generales communes a tous les objets
351 foreach(array_keys($infos_tables) as $t) {
352 foreach($all as $i=>$v)
353 if (in_array($i,array('tables_jointures','champs_versionnes'))){
354 $add = $all[$i];
355 // eviter les doublons de declaration de table jointure (ex des mots sur auteurs)
356 // pour les declarations generiques avec cles numeriques
357 if ($i=='tables_jointures' AND isset($infos_tables[$t][$i]) AND count($infos_tables[$t][$i])) {
358 $doublons = array_intersect($infos_tables[$t][$i],$add);
359 foreach($doublons as $d){
360 if (is_numeric(array_search($d,$infos_tables[$t][$i]))
361 AND is_numeric($k=array_search($d,$add)))
362 unset($add[$k]);
363 }
364 }
365 $infos_tables[$t][$i] = array_merge(isset($infos_tables[$t][$i])?$infos_tables[$t][$i]:array(),$add);
366 }
367 else
368 $infos_tables[$t][$i] = array_merge_recursive(isset($infos_tables[$t][$i])?$infos_tables[$t][$i]:array(),$all[$i]);
369 }
370
371 // completer les tables principales et auxiliaires
372 // avec celles declarees uniquement dans declarer_table_objets_sql
373 // pour assurer la compat en transition
374 foreach($infos_tables as $table=>$infos) {
375 $principale_ou_auxiliaire = ($infos['principale']?'tables_principales':'tables_auxiliaires');
376 // memoriser des champs eventuels declares par des plugins dans le pipeline tables_xxx
377 // qui a ete appelle avant
378 $mem = (isset($GLOBALS[$principale_ou_auxiliaire][$table])?$GLOBALS[$principale_ou_auxiliaire][$table]:array());
379 // l'ajouter au tableau
380 $GLOBALS[$principale_ou_auxiliaire][$table] = array();
381 if (isset($infos['field']) AND isset($infos['key'])){
382 foreach(array('field','key','join') as $k)
383 if (isset($infos_tables[$table][$k]))
384 $GLOBALS[$principale_ou_auxiliaire][$table][$k] = &$infos_tables[$table][$k];
385 }
386 else {
387 // ici on ne renvoie que les declarations, donc RIEN
388 // pour avoir la vrai description en base, il faut passer par trouver_table
389 $GLOBALS[$principale_ou_auxiliaire][$table] = array();
390 }
391 if (count($mem)){
392 foreach(array_keys($mem) as $k)
393 if (isset($GLOBALS[$principale_ou_auxiliaire][$table][$k]))
394 $GLOBALS[$principale_ou_auxiliaire][$table][$k] = array_merge($GLOBALS[$principale_ou_auxiliaire][$table][$k],$mem[$k]);
395 else
396 $GLOBALS[$principale_ou_auxiliaire][$table][$k] = $mem[$k];
397 }
398 }
399
400 // recuperer les interfaces (table_titre, table_date)
401 // on ne le fait que dans un second temps pour que table_objet soit fonctionnel
402 // dans le pipeline de declarer_tables_interfaces
403 include_spip('public/interfaces');
404 foreach(array_keys($infos_tables) as $t) {
405 $infos_tables[$t] = renseigner_table_objet_interfaces($t,$infos_tables[$t]);
406 }
407
408 $deja_la = false;
409 // signature
410 $md5 = md5(serialize($infos_tables));
411 }
412 if ($table_sql==="::md5")
413 return $md5;
414 if ($table_sql AND !isset($infos_tables[$table_sql])){
415 #$desc = renseigner_table_objet_sql($table_sql,$desc);
416 $desc = renseigner_table_objet_interfaces($table_sql,$desc);
417 return $desc;
418 }
419 if ($table_sql)
420 return isset($infos_tables[$table_sql])?$infos_tables[$table_sql]:array();
421
422 return $infos_tables;
423 }
424
425
426 /**
427 * Déclare les tables principales du Core
428 *
429 * Tables principales, hors objets éditoriaux.
430 *
431 * @param array $tables_principales
432 * Description des tables principales déjà déclarées
433 * @return void
434 **/
435 function base_serial(&$tables_principales){
436
437 $spip_jobs = array(
438 "id_job" => "bigint(21) NOT NULL",
439 "descriptif" => "text DEFAULT '' NOT NULL",
440 "fonction" => "varchar(255) NOT NULL", //nom de la fonction
441 "args"=> "longblob DEFAULT '' NOT NULL", // arguments
442 "md5args"=> "char(32) NOT NULL default ''", // signature des arguments
443 "inclure" => "varchar(255) NOT NULL", // fichier a inclure ou path/ pour charger_fonction
444 "priorite" => "smallint(6) NOT NULL default 0",
445 "date" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL", // date au plus tot
446 "status" => "tinyint NOT NULL default 1",
447 );
448
449 $spip_jobs_key = array(
450 "PRIMARY KEY" => "id_job",
451 "KEY date" => "date",
452 "KEY status" => "status",
453 );
454
455 /// Attention: mes_fonctions peut avoir deja defini cette variable
456 /// il faut donc rajouter, mais pas reinitialiser
457 $tables_principales['spip_jobs'] = array('field' => &$spip_jobs, 'key' => &$spip_jobs_key);
458 }
459
460
461 /**
462 * Déclare les tables auxiliaires du Core
463 *
464 * @param array $tables_auxiliaires
465 * Description des tables auxiliaires déjà déclarées
466 * @return void
467 **/
468 function base_auxiliaires(&$tables_auxiliaires){
469 $spip_resultats = array(
470 "recherche" => "char(16) DEFAULT '' NOT NULL",
471 "id" => "INT UNSIGNED NOT NULL",
472 "points" => "INT UNSIGNED DEFAULT '0' NOT NULL",
473 "table_objet" => "varchar(30) DEFAULT '' NOT NULL",
474 "serveur" => "char(16) DEFAULT '' NOT NULL", // hash md5 partiel du serveur de base ('' pour le serveur principal)
475 "maj" => "TIMESTAMP" );
476
477 $spip_resultats_key = array(
478 // pas de cle ni index, ca fait des insertions plus rapides et les requetes jointes utilisees en recheche ne sont pas plus lentes ...
479 );
480
481 $spip_auteurs_liens = array(
482 "id_auteur" => "bigint(21) DEFAULT '0' NOT NULL",
483 "id_objet" => "bigint(21) DEFAULT '0' NOT NULL",
484 "objet" => "VARCHAR (25) DEFAULT '' NOT NULL",
485 "vu" => "VARCHAR(6) DEFAULT 'non' NOT NULL");
486
487 $spip_auteurs_liens_key = array(
488 "PRIMARY KEY" => "id_auteur,id_objet,objet",
489 "KEY id_auteur" => "id_auteur",
490 "KEY id_objet" => "id_objet",
491 "KEY objet" => "objet",
492 );
493
494 $spip_meta = array(
495 "nom" => "VARCHAR (255) NOT NULL",
496 "valeur" => "text DEFAULT ''",
497 "impt" => "ENUM('non', 'oui') DEFAULT 'oui' NOT NULL",
498 "maj" => "TIMESTAMP");
499
500 $spip_meta_key = array(
501 "PRIMARY KEY" => "nom");
502
503 $spip_jobs_liens = array(
504 "id_job" => "bigint(21) DEFAULT '0' NOT NULL",
505 "id_objet" => "bigint(21) DEFAULT '0' NOT NULL",
506 "objet" => "VARCHAR (25) DEFAULT '' NOT NULL",
507 );
508
509 $spip_jobs_liens_key = array(
510 "PRIMARY KEY" => "id_job,id_objet,objet",
511 "KEY id_job" => "id_job");
512
513 $tables_auxiliaires['spip_auteurs_liens'] = array(
514 'field' => &$spip_auteurs_liens,
515 'key' => &$spip_auteurs_liens_key);
516
517 $tables_auxiliaires['spip_meta'] = array(
518 'field' => &$spip_meta,
519 'key' => &$spip_meta_key);
520 $tables_auxiliaires['spip_resultats'] = array(
521 'field' => &$spip_resultats,
522 'key' => &$spip_resultats_key);
523 $tables_auxiliaires['spip_jobs_liens'] = array(
524 'field' => &$spip_jobs_liens,
525 'key' => &$spip_jobs_liens_key);
526
527 }
528
529
530 /**
531 * Auto remplissage des informations non explicites
532 * sur un objet d'une table sql
533 *
534 * - table_objet
535 * - table_objet_surnoms
536 * - type
537 * - type_surnoms
538 * - url_voir
539 * - url_edit
540 * - icone_objet
541 *
542 * - texte_retour
543 * - texte_modifier
544 * - texte_creer
545 * - texte_creer_associer
546 * - texte_ajouter
547 * - texte_objets
548 * - texte_objet
549 *
550 * - info_aucun_objet
551 * - info_1_objet
552 * - info_nb_objets
553 *
554 * - texte_logo_objet
555 * - texte_langue_objet
556 * - texte_definir_comme_traduction_objet
557 *
558 * - principale
559 * - champs_contenu : utlisé pour générer l'affichage par défaut du contenu
560 * - editable
561 * - champs_editables : utilisé pour prendre en compte le post lors de l'édition
562 *
563 * - champs_versionnes
564 *
565 * statut
566 * statut_images
567 * statut_titres
568 * statut_textes_instituer
569 * texte_changer_statut
570 * aide_changer_statut
571 *
572 * - modeles : permet de declarer les modeles associes a cet objet
573 *
574 * Les infos non renseignées sont auto-déduites par conventions
575 * ou laissées vides
576 *
577 * @param string $table_sql
578 * @param array $infos
579 * @return array
580 */
581 function renseigner_table_objet_sql($table_sql,&$infos){
582 if (!isset($infos['type'])){
583 // si on arrive de base/trouver_table, on a la cle primaire :
584 // s'en servir pour extrapoler le type
585 if (isset($infos['key']["PRIMARY KEY"])){
586 $primary = $infos['key']["PRIMARY KEY"];
587 $primary = explode(',',$primary);
588 $primary = reset($primary);
589 $infos['type'] = preg_replace(',^spip_|^id_|s$,', '', $primary);
590 }
591 else
592 $infos['type'] = preg_replace(',^spip_|s$,', '', $table_sql);
593 }
594 if (!isset($infos['type_surnoms']))
595 $infos['type_surnoms'] = array();
596
597 if (!isset($infos['table_objet']))
598 $infos['table_objet'] = preg_replace(',^spip_,', '', $table_sql);
599 if (!isset($infos['table_objet_surnoms']))
600 $infos['table_objet_surnoms'] = array();
601
602 if (!isset($infos['principale']))
603 $infos['principale'] = (isset($GLOBALS['tables_principales'][$table_sql])?'oui':false);
604
605 // normaliser pour pouvoir tester en php $infos['principale']?
606 // et dans une boucle {principale=oui}
607 $infos['principale'] = (($infos['principale'] AND $infos['principale']!='non')?'oui':false);
608
609 // declarer et normaliser pour pouvoir tester en php $infos['editable']?
610 // et dans une boucle {editable=oui}
611 if (!isset($infos['editable'])) $infos['editable'] = 'oui';
612 $infos['editable'] = (($infos['editable'] AND $infos['editable']!='non')?'oui':false);
613
614 // les urls publiques sont par defaut page=type pour les tables principales, et rien pour les autres
615 // seules les exceptions sont donc a declarer
616 if (!isset($infos['page']))
617 $infos['page'] = ($infos['principale']?$infos['type']:'');
618
619 if (!isset($infos['url_voir']))
620 $infos['url_voir'] = $infos['type'];
621 if (!isset($infos['url_edit']))
622 $infos['url_edit'] = $infos['url_voir'].($infos['editable']?"_edit":'');
623 if (!isset($infos['icone_objet']))
624 $infos['icone_objet'] = $infos['type'];
625
626 // chaines de langue
627 // par defaut : objet:icone_xxx_objet
628 if (!isset($infos['texte_retour']))
629 $infos['texte_retour'] = 'icone_retour';
630 if (!isset($infos['texte_modifier']))
631 $infos['texte_modifier'] = $infos['type'].':'.'icone_modifier_'.$infos['type'];
632 if (!isset($infos['texte_creer']))
633 $infos['texte_creer'] = $infos['type'].':'.'icone_creer_'.$infos['type'];
634 if (!isset($infos['texte_creer_associer']))
635 $infos['texte_creer_associer'] = $infos['type'].':'.'texte_creer_associer_'.$infos['type'];
636 if (!isset($infos['texte_ajouter'])) // Ajouter un X
637 $infos['texte_ajouter'] = $infos['type'].':'.'texte_ajouter_'.$infos['type'];
638 if (!isset($infos['texte_objets']))
639 $infos['texte_objets'] = $infos['type'].':'.'titre_'.$infos['table_objet'];
640 if (!isset($infos['texte_objet']))
641 $infos['texte_objet'] = $infos['type'].':'.'titre_'.$infos['type'];
642 if (!isset($infos['texte_logo_objet'])) // objet:titre_logo_objet "Logo de ce X"
643 $infos['texte_logo_objet'] = $infos['type'].':'.'titre_logo_'.$infos['type'];
644 if (!isset($infos['texte_langue_objet'])) // objet:texte_langue_objet "Langue de ce X"
645 $infos['texte_langue_objet'] = $infos['type'].':'.'titre_langue_'.$infos['type'];
646 if (!isset($infos['texte_definir_comme_traduction_objet'])) // "Ce X est une traduction du X numéro :"
647 $infos['texte_definir_comme_traduction_objet'] = $infos['type'].':'.'texte_definir_comme_traduction_'.$infos['type'];
648
649
650 // objet:info_aucun_objet
651 if (!isset($infos['info_aucun_objet']))
652 $infos['info_aucun_objet'] = $infos['type'].':'.'info_aucun_'.$infos['type'];
653 // objet:info_1_objet
654 if (!isset($infos['info_1_objet']))
655 $infos['info_1_objet'] = $infos['type'].':'.'info_1_'.$infos['type'];
656 // objet:info_nb_objets
657 if (!isset($infos['info_nb_objets']))
658 $infos['info_nb_objets'] = $infos['type'].':'.'info_nb_'.$infos['table_objet'];
659
660
661 if (!isset($infos['champs_editables']))
662 $infos['champs_editables'] = array();
663 if (!isset($infos['champs_versionnes']))
664 $infos['champs_versionnes'] = array();
665 if (!isset($infos['rechercher_champs']))
666 $infos['rechercher_champs'] = array();
667 if (!isset($infos['rechercher_jointures']))
668 $infos['rechercher_jointures'] = array();
669
670 if (!isset($infos['modeles']))
671 $infos['modeles'] = array($infos['type']);
672
673 return $infos;
674 }
675
676 /**
677 * Renseigner les infos d'interface compilateur pour les tables objets
678 * complete la declaration precedente
679 *
680 * titre
681 * date
682 * statut
683 * tables_jointures
684 *
685 * @param $table_sql
686 * @param $infos
687 * @return array
688 */
689 function renseigner_table_objet_interfaces($table_sql,&$infos){
690 if (!isset($infos['titre'])){
691 if (isset($infos['table_objet']) AND isset($GLOBALS['table_titre'][$infos['table_objet']]))
692 $infos['titre'] = $GLOBALS['table_titre'][$infos['table_objet']];
693 else {
694 $infos['titre'] = ((isset($infos['field']['titre']))?"titre,":"'' as titre,");
695 $infos['titre'] .= ((isset($infos['field']['lang']))?"lang":"'' as lang");
696 }
697 }
698 if (!isset($infos['date'])){
699 if (isset($infos['table_objet']) and isset($GLOBALS['table_date'][$infos['table_objet']]))
700 $infos['date'] = $GLOBALS['table_date'][$infos['table_objet']];
701 else
702 $infos['date'] = ((isset($infos['field']['date']))?"date":'');
703 }
704 if (!isset($infos['statut']))
705 $infos['statut'] = isset($GLOBALS['table_statut'][$table_sql]) ? $GLOBALS['table_statut'][$table_sql] : '';
706 if (!isset($infos['tables_jointures']))
707 $infos['tables_jointures'] = array();
708 if (isset($GLOBALS['tables_jointures'][$table_sql]))
709 $infos['tables_jointures'] = array_merge($infos['tables_jointures'],$GLOBALS['tables_jointures'][$table_sql]);
710 return $infos;
711 }
712
713 /**
714 * Retourne la liste des tables principales et leurs descriptions
715 *
716 * @api
717 * @return array
718 * Liste et descriptions des tables principales
719 **/
720 function lister_tables_principales(){
721 static $done = false;
722 if (!$done OR !count($GLOBALS['tables_principales'])){
723 lister_tables_objets_sql();
724 $done = true;
725 }
726 return $GLOBALS['tables_principales'];
727 }
728
729 /**
730 * Retourne la liste des tables auxiliaires et leurs descriptions
731 *
732 * @api
733 * @return array
734 * Liste et descriptions des tables auxiliaires
735 **/
736 function lister_tables_auxiliaires(){
737 static $done = false;
738 if (!$done OR !count($GLOBALS['tables_auxiliaires'])){
739 lister_tables_objets_sql();
740 $done = true;
741 }
742 return $GLOBALS['tables_auxiliaires'];
743 }
744
745 /**
746 * Recenser les surnoms de table_objet
747 * @return array
748 */
749 function lister_tables_objets_surnoms(){
750 static $surnoms = null;
751 static $md5 = null;
752 if (!$surnoms
753 OR $md5 != lister_tables_objets_sql('::md5')){
754 // passer dans un pipeline qui permet aux plugins de declarer leurs exceptions
755 // pour compatibilite, car il faut dorenavent utiliser
756 // declarer_table_objets_sql
757 $surnoms = pipeline('declarer_tables_objets_surnoms',
758 array(
759 # pour les modeles
760 # a enlever ?
761 'doc' => 'documents',
762 'img' => 'documents',
763 'emb' => 'documents',
764 ));
765 $infos_tables = lister_tables_objets_sql();
766 foreach($infos_tables as $t=>$infos){
767 // cas de base type=>table
768 // et preg_replace(',^spip_|^id_|s$,',table)=>table
769 if ($infos['table_objet']){ // securite, si la fonction est appelee trop tot, c'est vide
770 // optimisations pour table_objet
771 //$surnoms[$infos['type']] = $infos['table_objet'];
772 $surnoms[preg_replace(',^spip_|^id_|s$,', '', $infos['table_objet'])] = $infos['table_objet'];
773 $surnoms[preg_replace(',^spip_|^id_|s$,', '', $infos['type'])] = $infos['table_objet'];
774 if (is_array($infos['table_objet_surnoms']) AND count($infos['table_objet_surnoms']))
775 foreach($infos['table_objet_surnoms'] as $surnom)
776 $surnoms[$surnom] = $infos['table_objet'];
777 }
778 }
779 $md5 = lister_tables_objets_sql('::md5');
780 }
781 return $surnoms;
782 }
783
784 /**
785 * Recenser les surnoms de table_objet
786 * @return array
787 */
788 function lister_types_surnoms(){
789 static $surnoms = null;
790 static $md5 = null;
791 if (!$surnoms
792 OR $md5 != lister_tables_objets_sql('::md5')){
793 // passer dans un pipeline qui permet aux plugins de declarer leurs exceptions
794 // pour compatibilite, car il faut dorenavent utiliser
795 // declarer_table_objets_sql
796 $surnoms = pipeline('declarer_type_surnoms', array('racine-site'=>'site'));
797 $infos_tables = lister_tables_objets_sql();
798 foreach($infos_tables as $t=>$infos){
799 if ($infos['type']){ // securite, si la fonction est appelee trop tot, c'est vide
800 // optimisations pour objet_type
801 //$surnoms[$infos['type']] = $infos['type'];
802 $surnoms[preg_replace(',^spip_|^id_|s$,', '', $infos['table_objet'])] = $infos['type'];
803 $surnoms[preg_replace(',^spip_|^id_|s$,', '', $infos['type'])] = $infos['type'];
804 // surnoms declares
805 if (is_array($infos['type_surnoms']) AND count($infos['type_surnoms']))
806 foreach($infos['type_surnoms'] as $surnom)
807 $surnoms[$surnom] = $infos['type'];
808 }
809 }
810 $md5 = lister_tables_objets_sql('::md5');
811 }
812 return $surnoms;
813 }
814
815 function lister_tables_spip($serveur=''){
816 static $tables = array();
817 if (!isset($tables[$serveur])){
818 $tables[$serveur] = array();
819 if (!function_exists("sql_alltable"))
820 include_spip("base/abstract_sql");
821 $ts = sql_alltable(null,$serveur); // toutes les tables "spip_" (ou prefixe perso)
822 $connexion = $GLOBALS['connexions'][$serveur ? $serveur : 0];
823 $spip = $connexion['prefixe'] . '_';
824 foreach ($ts as $t){
825 $t = substr($t,strlen($spip));
826 $tables[$serveur]["spip_$t"] = $t;
827 }
828 }
829 return $tables[$serveur];
830 }
831
832 /**
833 * Retrouve le nom d'objet à partir de la table
834 *
835 * - spip_articles -> articles
836 * - id_article -> articles
837 * - article -> articles
838 *
839 * @api
840 * @param string $type
841 * Nom de la table SQL (le plus souvent)
842 * Tolère un nom de clé primaire.
843 * @param string $serveur
844 * Nom du connecteur
845 * @return string
846 * Nom de l'objet
847 **/
848 function table_objet($type,$serveur='') {
849 $surnoms = lister_tables_objets_surnoms();
850 $type = preg_replace(',^spip_|^id_|s$,', '', $type);
851 if (!$type) return;
852 if (isset($surnoms[$type]))
853 return $surnoms[$type];
854
855 if ($serveur!==false){
856 $t=lister_tables_spip($serveur);
857 $trouver_table = charger_fonction('trouver_table', 'base');
858 $typetrim = rtrim($type,'s')."s";
859 if (
860 (isset($t[$typetrim]) OR in_array($typetrim,$t))
861 AND ($desc = $trouver_table(rtrim($type,'s')."s",$serveur))
862 )
863 return $desc['id_table'];
864 elseif (
865 (isset($t[$type]) OR in_array($type,$t))
866 AND ($desc = $trouver_table($type,$serveur))
867 )
868 return $desc['id_table'];
869
870 spip_log( 'table_objet('.$type.') calculee sans verification');
871 }
872
873 return rtrim($type,'s')."s"; # cas historique ne devant plus servir, sauf si $serveur=false
874 }
875
876 /**
877 * Retrouve la table sql à partir de l'objet ou du type
878 *
879 * - articles -> spip_articles
880 * - article -> spip_articles
881 * - id_article -> spip_articles
882 *
883 * @api
884 * @param string $type
885 * Nom ou type de l'objet
886 * Tolère un nom de clé primaire.
887 * @param string $serveur
888 * Nom du connecteur
889 * @return string
890 * Nom de la table SQL
891 **/
892 function table_objet_sql($type,$serveur='') {
893 global $table_des_tables;
894 $nom = table_objet($type, $serveur);
895 if (!isset($table_des_tables['articles'])) // eviter de multiples inclusions
896 include_spip('public/interfaces');
897 if (isset($table_des_tables[$nom])) {
898 $nom = $table_des_tables[$nom];
899 $nom = "spip_$nom";
900 }
901 else {
902 $infos_tables = lister_tables_objets_sql();
903 if (isset($infos_tables["spip_$nom"]))
904 $nom = "spip_$nom";
905 elseif($serveur!==false) {
906 $t=lister_tables_spip($serveur);
907 if (isset($t[$nom]) OR in_array($nom,$t)){
908 $trouver_table = charger_fonction('trouver_table', 'base');
909 if ($desc = $trouver_table($nom,$serveur))
910 return $desc['table_sql'];
911 }
912 }
913 }
914
915 return $nom ;
916 }
917
918 /**
919 * Retrouve la clé primaire à partir du nom d'objet ou de table
920 *
921 * - articles -> id_article
922 * - article -> id_article
923 * - spip_articles -> id_article
924 *
925 * @api
926 * @param string $type
927 * Nom de la table SQL ou de l'objet
928 * @param string $serveur
929 * Nom du connecteur
930 * @return string
931 * Nom de la clé primaire
932 **/
933 function id_table_objet($type,$serveur='') {
934 static $trouver_table = null;
935 $type = objet_type($type,$serveur);
936 if (!$type) return;
937 $t = table_objet($type);
938 if (!$trouver_table)
939 $trouver_table = charger_fonction('trouver_table', 'base');
940
941 $ts=lister_tables_spip($serveur);
942 if (in_array($t,$ts)){
943 $desc = $trouver_table($t,$serveur);
944 if (isset($desc['key']['PRIMARY KEY']))
945 return $desc['key']['PRIMARY KEY'];
946 if (!$desc OR isset($desc['field']["id_$type"]))
947 return "id_$type";
948 // sinon renvoyer le premier champ de la table...
949 $keys = array_keys($desc['field']);
950 return array_shift($keys);
951 }
952 return "id_$type";
953 }
954
955 /**
956 * Retrouve le type d'objet à partir du nom d'objet ou de table
957 *
958 * - articles -> article
959 * - spip_articles -> article
960 * - id_article -> article
961 *
962 * @api
963 * @param string $table_objet
964 * Nom de l'objet ou de la table SQL
965 * @param string $serveur
966 * Nom du connecteur
967 * @return string
968 * Type de l'objet
969 **/
970 function objet_type($table_objet, $serveur=''){
971 if (!$table_objet) return;
972 $surnoms = lister_types_surnoms();
973
974 // scenario de base
975 // le type est decline a partir du nom de la table en enlevant le prefixe eventuel
976 // et la marque du pluriel
977 // on accepte id_xx en entree aussi
978 $type = preg_replace(',^spip_|^id_|s$,', '', $table_objet);
979 if (isset($surnoms[$type]))
980 return $surnoms[$type];
981
982 // securite : eliminer les caracteres non \w
983 $type = preg_replace(',[^\w-],','',$type);
984
985 // si le type redonne bien la table c'est bon
986 // oui si table_objet ressemblait deja a un type
987 if ( $type==$table_objet
988 OR (table_objet($type,$serveur)==$table_objet)
989 OR (table_objet_sql($type,$serveur)==$table_objet))
990 return $type;
991
992 // si on ne veut pas chercher en base
993 if ($serveur===false)
994 return $type;
995
996 // sinon on passe par la cle primaire id_xx pour trouver le type
997 // car le s a la fin est incertain
998 // notamment en cas de pluriel derogatoire
999 // id_jeu/spip_jeux id_journal/spip_journaux qui necessitent tout deux
1000 // une declaration jeu => jeux, journal => journaux
1001 // dans le pipeline declarer_tables_objets_surnoms
1002 $trouver_table = charger_fonction('trouver_table', 'base');
1003 $ts=lister_tables_spip($serveur);
1004 if (in_array($table_objet,$ts))
1005 $desc = $trouver_table($table_objet);
1006 if (!$desc AND in_array($table_objet=table_objet($type,$serveur),$ts))
1007 $desc = $trouver_table($table_objet,$serveur);
1008 // si le type est declare : bingo !
1009 if ($desc AND isset($desc['type']))
1010 return $desc['type'];
1011
1012 // on a fait ce qu'on a pu
1013 return $type;
1014 }
1015
1016 /**
1017 * Determininer si un objet est publie ou non
1018 *
1019 * On se base pour cela sur sa declaration de statut
1020 * pour des cas particuliers non declarables, on permet de fournir une fonction
1021 * base_xxxx_test_si_publie qui sera appele par la fonction
1022 *
1023 * @param string $objet
1024 * @param int $id_objet
1025 * @param string $serveur
1026 * @return bool
1027 */
1028 function objet_test_si_publie($objet,$id_objet, $serveur=''){
1029 // voir si une fonction est definie pour faire le boulot
1030 // elle a la priorite dans ce cas
1031 if ($f = charger_fonction($objet."_test_si_publie","base",true))
1032 return $f($objet,$id_objet, $serveur);
1033
1034 // sinon on se fie a la declaration de l'objet si presente
1035 $id_table = $table_objet = table_objet($objet);
1036 $id_table_objet = id_table_objet($objet, $serveur);
1037 $trouver_table = charger_fonction('trouver_table', 'base');
1038 if ($desc = $trouver_table($table_objet, $serveur)
1039 AND isset($desc['statut'])
1040 AND $desc['statut']){
1041 $boucle = new Boucle();
1042 $boucle->show = $desc;
1043 $boucle->nom = 'objet_test_si_publie';
1044 $boucle->id_boucle = $id_table;
1045 $boucle->id_table = $id_table;
1046 $boucle->sql_serveur = $serveur;
1047 $boucle->select[] = $id_table_objet;
1048 $boucle->from[$table_objet] = table_objet_sql($objet, $serveur);
1049 $boucle->where[] = $id_table.".".$id_table_objet.'='.intval($id_objet);
1050
1051 include_spip('public/compiler');
1052 include_spip('public/composer');
1053 instituer_boucle($boucle, false, true);
1054 $res = calculer_select($boucle->select,$boucle->from,$boucle->from_type,$boucle->where,$boucle->join,$boucle->group,$boucle->order,$boucle->limit,$boucle->having,$table_objet,$id_table,$serveur);
1055 if (sql_fetch($res))
1056 return true;
1057 return false;
1058 }
1059
1060 // si pas d'info statut ni de fonction : l'objet est publie
1061 return true;
1062 }