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