Completed
Push — master ( 8971b0...ad49ff )
by cam
04:10
created

editer_objet.php ➔ objet_lire()   F

Complexity

Conditions 20
Paths 7440

Size

Total Lines 96

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
nc 7440
nop 3
dl 0
loc 96
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/***************************************************************************\
4
 *  SPIP, Systeme de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright (c) 2001-2019                                                *
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
 * Gestion générique de modification des objets éditoriaux
15
 *
16
 * @package SPIP\Core\Edition
17
 */
18
19
if (!defined('_ECRIRE_INC_VERSION')) {
20
	return;
21
}
22
23
/**
24
 * Point d'entrée d'édition d'un objet
25
 *
26
 * On ne peut entrer que par un appel en fournissant $id et $objet
27
 * ou avec un argument d'action sécurisée de type "objet/id"
28
 *
29
 * @param int $id
0 ignored issues
show
Documentation introduced by
Should the type for parameter $id not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
30
 * @param string $objet
0 ignored issues
show
Documentation introduced by
Should the type for parameter $objet not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
31
 * @param array $set
0 ignored issues
show
Documentation introduced by
Should the type for parameter $set not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
32
 * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be null|array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
33
 */
34
function action_editer_objet_dist($id = null, $objet = null, $set = null) {
35
36
	// appel direct depuis une url avec arg = "objet/id"
37
	if (is_null($id) or is_null($objet)) {
38
		$securiser_action = charger_fonction('securiser_action', 'inc');
39
		$arg = $securiser_action();
40
		list($objet, $id) = array_pad(explode("/", $arg, 2), 2, null);
41
	}
42
43
	// appel incorrect ou depuis une url erronnée interdit
44
	if (is_null($id) or is_null($objet)) {
45
		include_spip('inc/minipres');
46
		echo minipres(_T('info_acces_interdit'));
47
		die();
48
	}
49
50
	// si id n'est pas un nombre, c'est une creation
51
	// mais on verifie qu'on a toutes les donnees qu'il faut.
52
	if (!$id = intval($id)) {
53
		// on ne sait pas si un parent existe mais on essaye
54
		$id_parent = _request('id_parent');
55
		$id = objet_inserer($objet, $id_parent);
56
	}
57
58
	if (!($id = intval($id)) > 0) {
59
		return array($id, _L('echec enregistrement en base'));
60
	}
61
62
	// Enregistre l'envoi dans la BD
63
	$err = objet_modifier($objet, $id, $set);
64
65
	return array($id, $err);
66
}
67
68
/**
69
 * Appelle toutes les fonctions de modification d'un objet
70
 * $err est un message d'erreur eventuelle
71
 *
72
 * @param string $objet
73
 * @param int $id
74
 * @param array|null $set
75
 * @return mixed|string
76
 */
77
function objet_modifier($objet, $id, $set = null) {
78
	if (include_spip('action/editer_' . $objet)
79
		and function_exists($modifier = $objet . "_modifier")
80
	) {
81
		return $modifier($id, $set);
82
	}
83
84
	$table_sql = table_objet_sql($objet);
85
	$trouver_table = charger_fonction('trouver_table', 'base');
86
	$desc = $trouver_table($table_sql);
87 View Code Duplication
	if (!$desc or !isset($desc['field'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
88
		spip_log("Objet $objet inconnu dans objet_modifier", _LOG_ERREUR);
89
90
		return _L("Erreur objet $objet inconnu");
91
	}
92
	include_spip('inc/modifier');
93
94
	$champ_date = '';
95 View Code Duplication
	if (isset($desc['date']) and $desc['date']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
96
		$champ_date = $desc['date'];
97
	} elseif (isset($desc['field']['date'])) {
98
		$champ_date = 'date';
99
	}
100
101
	$white = array_keys($desc['field']);
102
	// on ne traite pas la cle primaire par defaut, notamment car
103
	// sur une creation, id_x vaut 'oui', et serait enregistre en id_x=0 dans la base
104
	$white = array_diff($white, array($desc['key']['PRIMARY KEY']));
105
106
	if (isset($desc['champs_editables']) and is_array($desc['champs_editables'])) {
107
		$white = $desc['champs_editables'];
108
	}
109
	$c = collecter_requests(
110
	// white list
111
		$white,
112
		// black list
113
		array($champ_date, 'statut', 'id_parent', 'id_secteur'),
114
		// donnees eventuellement fournies
115
		$set
116
	);
117
118
	// Si l'objet est publie, invalider les caches et demander sa reindexation
119
	if (objet_test_si_publie($objet, $id)) {
120
		$invalideur = "id='$objet/$id'";
121
		$indexation = true;
122
	} else {
123
		$invalideur = "";
124
		$indexation = false;
125
	}
126
127
	if ($err = objet_modifier_champs($objet, $id,
128
		array(
129
			'data' => $set,
130
			'nonvide' => '',
131
			'invalideur' => $invalideur,
132
			'indexation' => $indexation,
133
			// champ a mettre a date('Y-m-d H:i:s') s'il y a modif
134
			'date_modif' => (isset($desc['field']['date_modif']) ? 'date_modif' : '')
135
		),
136
		$c)
137
	) {
138
		return $err;
139
	}
140
141
	// Modification de statut, changement de rubrique ?
142
	// FIXME: Ici lorsqu'un $set est passé, la fonction collecter_requests() retourne tout
143
	//         le tableau $set hors black liste, mais du coup on a possiblement des champs en trop. 
144
	$c = collecter_requests(array($champ_date, 'statut', 'id_parent'), array(), $set);
145
	$err = objet_instituer($objet, $id, $c);
146
147
	return $err;
148
}
149
150
/**
151
 * Insere en base un objet generique
152
 *
153
 * @param string $objet
154
 * @param int $id_parent
0 ignored issues
show
Documentation introduced by
Should the type for parameter $id_parent not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
155
 * @param array|null $set
156
 * @global array $GLOBALS ['visiteur_session']
157
 * @global array $GLOBALS ['meta']
158
 * @global string $GLOBALS ['spip_lang']
159
 * @return bool|int
160
 */
161
function objet_inserer($objet, $id_parent = null, $set = null) {
162
	if (include_spip('action/editer_' . $objet)
163
		and function_exists($inserer = $objet . "_inserer")
164
	) {
165
		return $inserer($id_parent, $set);
166
	}
167
168
	$table_sql = table_objet_sql($objet);
169
	$trouver_table = charger_fonction('trouver_table', 'base');
170
	$desc = $trouver_table($table_sql);
171
	if (!$desc or !isset($desc['field'])) {
172
		return 0;
173
	}
174
175
	$lang_rub = "";
176
	$champs = array();
177
	if (isset($desc['field']['id_rubrique'])) {
178
		// Si id_rubrique vaut 0 ou n'est pas definie, creer l'objet
179
		// dans la premiere rubrique racine
180 View Code Duplication
		if (!$id_rubrique = intval($id_parent)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
			$row = sql_fetsel("id_rubrique, id_secteur, lang", "spip_rubriques", "id_parent=0", '', '0+titre,titre', "1");
182
			$id_rubrique = $row['id_rubrique'];
183
		} else {
184
			$row = sql_fetsel("lang, id_secteur", "spip_rubriques", "id_rubrique=" . intval($id_rubrique));
185
		}
186
187
		$champs['id_rubrique'] = $id_rubrique;
188
		if (isset($desc['field']['id_secteur'])) {
189
			$champs['id_secteur'] = $row['id_secteur'];
190
		}
191
		$lang_rub = $row['lang'];
192
	}
193
194
	// La langue a la creation : si les liens de traduction sont autorises
195
	// dans les rubriques, on essaie avec la langue de l'auteur,
196
	// ou a defaut celle de la rubrique
197
	// Sinon c'est la langue de la rubrique qui est choisie + heritee
198
	if (isset($desc['field']['lang']) and !empty($GLOBALS['meta']['multi_objets']) and in_array($table_sql,
199
			explode(',', $GLOBALS['meta']['multi_objets']))
200
	) {
201
		lang_select($GLOBALS['visiteur_session']['lang']);
202
		if (in_array($GLOBALS['spip_lang'],
203
			explode(',', $GLOBALS['meta']['langues_multilingue']))) {
204
			$champs['lang'] = $GLOBALS['spip_lang'];
205
			if (isset($desc['field']['langue_choisie'])) {
206
				$champs['langue_choisie'] = 'oui';
207
			}
208
		}
209
	} elseif (isset($desc['field']['lang']) and isset($desc['field']['langue_choisie'])) {
210
		$champs['lang'] = ($lang_rub ? $lang_rub : $GLOBALS['meta']['langue_site']);
211
		$champs['langue_choisie'] = 'non';
212
	}
213
214
	if (isset($desc['field']['statut'])) {
215
		if (isset($desc['statut_textes_instituer'])) {
216
			$cles_statut = array_keys($desc['statut_textes_instituer']);
217
			$champs['statut'] = reset($cles_statut);
218
		} else {
219
			$champs['statut'] = 'prepa';
220
		}
221
	}
222
223
224
	if ((isset($desc['date']) and $d = $desc['date']) or isset($desc['field'][$d = 'date'])) {
225
		$champs[$d] = date('Y-m-d H:i:s');
226
	}
227
228
	if ($set) {
229
		$champs = array_merge($champs, $set);
230
	}
231
232
	// Envoyer aux plugins
233
	$champs = pipeline('pre_insertion',
234
		array(
235
			'args' => array(
236
				'table' => $table_sql,
237
				'id_parent' => $id_parent,
238
			),
239
			'data' => $champs
240
		)
241
	);
242
243
	$id = sql_insertq($table_sql, $champs);
244
245
	if ($id) {
246
		// controler si le serveur n'a pas renvoye une erreur
247
		// et associer l'auteur sinon
248
		// si la table n'a pas deja un champ id_auteur
249
		// et si le form n'a pas poste un id_auteur (meme vide, ce qui sert a annuler cette auto association)
250
		if ($id > 0
251
			and !isset($desc['field']['id_auteur'])
252
		) {
253
			$id_auteur = ((is_null(_request('id_auteur')) and isset($GLOBALS['visiteur_session']['id_auteur'])) ?
254
				$GLOBALS['visiteur_session']['id_auteur']
255
				: _request('id_auteur'));
256
			if ($id_auteur) {
257
				include_spip('action/editer_auteur');
258
				auteur_associer($id_auteur, array($objet => $id));
259
			}
260
		}
261
262
		pipeline('post_insertion',
263
			array(
264
				'args' => array(
265
					'table' => $table_sql,
266
					'id_parent' => $id_parent,
267
					'id_objet' => $id,
268
				),
269
				'data' => $champs
270
			)
271
		);
272
273
	}
274
275
	return $id;
276
}
277
278
279
/**
280
 * Modifie le statut et/ou la date d'un objet
281
 *
282
 * @param string $objet
283
 * @param int $id
284
 * @param array $c
285
 *   $c est un array ('statut', 'id_parent' = changement de rubrique)
286
 *   statut et rubrique sont lies, car un admin restreint peut deplacer
287
 *   un objet publie vers une rubrique qu'il n'administre pas
288
 * @param bool $calcul_rub
289
 * @return string
290
 */
291
function objet_instituer($objet, $id, $c, $calcul_rub = true) {
292
	if (include_spip('action/editer_' . $objet)
293
		and function_exists($instituer = $objet . "_instituer")
294
	) {
295
		return $instituer($id, $c, $calcul_rub);
296
	}
297
298
	$table_sql = table_objet_sql($objet);
299
	$trouver_table = charger_fonction('trouver_table', 'base');
300
	$desc = $trouver_table($table_sql);
301
	if (!$desc or !isset($desc['field'])) {
302
		return _L("Impossible d'instituer $objet : non connu en base");
303
	}
304
305
	include_spip('inc/autoriser');
306
	include_spip('inc/rubriques');
307
	include_spip('inc/modifier');
308
309
	$sel = array();
310
	$sel[] = (isset($desc['field']['statut']) ? "statut" : "'' as statut");
311
312
	$champ_date = '';
313 View Code Duplication
	if (isset($desc['date']) and $desc['date']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
314
		$champ_date = $desc['date'];
315
	} elseif (isset($desc['field']['date'])) {
316
		$champ_date = 'date';
317
	}
318
319
	$sel[] = ($champ_date ? "$champ_date as date" : "'' as date");
320
	$sel[] = (isset($desc['field']['id_rubrique']) ? 'id_rubrique' : "0 as id_rubrique");
321
322
	$row = sql_fetsel($sel, $table_sql, id_table_objet($objet) . '=' . intval($id));
323
324
	$id_rubrique = $row['id_rubrique'];
325
	$statut_ancien = $statut = $row['statut'];
326
	$date_ancienne = $date = $row['date'];
327
	$champs = array();
328
329
	$d = ($date and isset($c[$champ_date])) ? $c[$champ_date] : null;
330
	$s = (isset($desc['field']['statut']) and isset($c['statut'])) ? $c['statut'] : $statut;
331
332
	// cf autorisations dans inc/instituer_objet
333
	if ($s != $statut or ($d and $d != $date)) {
334
		if ($id_rubrique ?
335
			autoriser('publierdans', 'rubrique', $id_rubrique)
336
			:
337
			autoriser('instituer', $objet, $id, null, array('statut' => $s))
338
		) {
339
			$statut = $champs['statut'] = $s;
340 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
341
			if ($s != 'publie' and autoriser('modifier', $objet, $id)) {
342
				$statut = $champs['statut'] = $s;
343
			} else {
344
				spip_log("editer_objet $id refus " . join(' ', $c));
345
			}
346
		}
347
348
		// En cas de publication, fixer la date a "maintenant"
349
		// sauf si $c commande autre chose
350
		// ou si l'objet est deja date dans le futur
351
		// En cas de proposition d'un objet (mais pas depublication), idem
352
		if ($champ_date) {
353 View Code Duplication
			if ($champs['statut'] == 'publie'
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
354
				or ($champs['statut'] == 'prop' and !in_array($statut_ancien, array('publie', 'prop')))
355
				or $d
356
			) {
357
				if ($d or strtotime($d = $date) > time()) {
358
					$champs[$champ_date] = $date = $d;
359
				} else {
360
					$champs[$champ_date] = $date = date('Y-m-d H:i:s');
361
				}
362
			}
363
		}
364
	}
365
366
	// Verifier que la rubrique demandee existe et est differente
367
	// de la rubrique actuelle
368 View Code Duplication
	if ($id_rubrique
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
369
		and isset($c['id_parent'])
370
		and $id_parent = $c['id_parent']
371
		and $id_parent != $id_rubrique
372
		and (sql_fetsel('1', "spip_rubriques", "id_rubrique=" . intval($id_parent)))
373
	) {
374
		$champs['id_rubrique'] = $id_parent;
375
376
		// si l'objet etait publie
377
		// et que le demandeur n'est pas admin de la rubrique
378
		// repasser l'objet en statut 'propose'.
379
		if ($statut == 'publie'
380
			and !autoriser('publierdans', 'rubrique', $id_rubrique)
381
		) {
382
			$champs['statut'] = 'prop';
383
		}
384
	}
385
386
387
	// Envoyer aux plugins
388
	$champs = pipeline('pre_edition',
389
		array(
390
			'args' => array(
391
				'table' => $table_sql,
392
				'id_objet' => $id,
393
				'action' => 'instituer',
394
				'statut_ancien' => $statut_ancien,
395
				'date_ancienne' => $date_ancienne,
396
				'id_parent_ancien' => $id_rubrique,
397
			),
398
			'data' => $champs
399
		)
400
	);
401
402
	if (!count($champs)) {
403
		return '';
404
	}
405
406
	// Envoyer les modifs.
407
	objet_editer_heritage($objet, $id, $id_rubrique, $statut_ancien, $champs, $calcul_rub);
408
409
	// Invalider les caches
410
	include_spip('inc/invalideur');
411
	suivre_invalideur("id='$objet/$id'");
412
413
	/*
414
	if ($date) {
415
		$t = strtotime($date);
416
		$p = @$GLOBALS['meta']['date_prochain_postdate'];
417
		if ($t > time() AND (!$p OR ($t < $p))) {
418
			ecrire_meta('date_prochain_postdate', $t);
419
		}
420
	}*/
421
422
	// Pipeline
423
	pipeline('post_edition',
424
		array(
425
			'args' => array(
426
				'table' => $table_sql,
427
				'id_objet' => $id,
428
				'action' => 'instituer',
429
				'statut_ancien' => $statut_ancien,
430
				'date_ancienne' => $date_ancienne,
431
				'id_parent_ancien' => $id_rubrique,
432
			),
433
			'data' => $champs
434
		)
435
	);
436
437
	// Notifications
438 View Code Duplication
	if ($notifications = charger_fonction('notifications', 'inc')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
439
		$notifications("instituer$objet", $id,
440
			array('statut' => $statut, 'statut_ancien' => $statut_ancien, 'date' => $date, 'date_ancienne' => $date_ancienne)
441
		);
442
	}
443
444
	return ''; // pas d'erreur
445
}
446
447
/**
448
 * Fabrique la requete d'institution de l'objet, avec champs herites
449
 *
450
 * @param string $objet
451
 * @param int $id
452
 * @param int $id_rubrique
453
 * @param string $statut
454
 * @param array $champs
455
 * @param bool $cond
456
 * @return void
457
 */
458
function objet_editer_heritage($objet, $id, $id_rubrique, $statut, $champs, $cond = true) {
459
	$table_sql = table_objet_sql($objet);
460
	$trouver_table = charger_fonction('trouver_table', 'base');
461
	$desc = $trouver_table($table_sql);
462
463
	// Si on deplace l'objet
464
	// changer aussi son secteur et sa langue (si heritee)
465
	if (isset($champs['id_rubrique'])) {
466
467
		$row_rub = sql_fetsel("id_secteur, lang", "spip_rubriques", "id_rubrique=" . sql_quote($champs['id_rubrique']));
468
		$langue = $row_rub['lang'];
469
470
		if (isset($desc['field']['id_secteur'])) {
471
			$champs['id_secteur'] = $row_rub['id_secteur'];
472
		}
473
474
		if (isset($desc['field']['lang']) and isset($desc['field']['langue_choisie'])) {
475 View Code Duplication
			if (sql_fetsel('1', $table_sql,
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
476
				id_table_objet($objet) . "=" . intval($id) . " AND langue_choisie<>'oui' AND lang<>" . sql_quote($langue))) {
477
				$champs['lang'] = $langue;
478
			}
479
		}
480
	}
481
482
	if (!$champs) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $champs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
483
		return;
484
	}
485
	sql_updateq($table_sql, $champs, id_table_objet($objet) . '=' . intval($id));
486
487
	// Changer le statut des rubriques concernees
488
	if ($cond) {
489
		include_spip('inc/rubriques');
490
		//$postdate = ($GLOBALS['meta']["post_dates"] == "non" AND isset($champs['date']) AND (strtotime($champs['date']) < time()))?$champs['date']:false;
491
		$postdate = false;
492
		calculer_rubriques_if($id_rubrique, $champs, $statut, $postdate);
493
	}
494
}
495
496
497
/**
498
 * Lit un objet donné connu par son id ou par un identifiant textuel unique et renvoie tout ou partie de sa
499
 * description.
500
 * Il est possible pour un objet donné de fournir la fonction `<objet>_lire_champs` qui renvoie simplement tous les
501
 * champs de l'objet concerné sans aucun autre traitement. Sinon, l'appel SQL est réalisé par l'API.
502
 *
503
 * @param string     $objet     Type d'objet (comme article ou rubrique)
504
 * @param int|string $valeur_id Valeur du champ identifiant
505
 * @param array      $options   Tableau d'options dont les index possibles sont:
506
 *                              - informations : liste des champs à renvoyer. Si absent ou vide la fonction
507
 *                                renvoie tous les champs.
508
 *                              - champ_id : nom du champ utilisé comme identifiant de l'objet. Si absent ou vide on
509
 *                                utilise l'id défini dans la déclaration de l'objet.
510
 *
511
 * @return array|mixed
512
 */
513
function objet_lire($objet, $valeur_id, $options = array()) {
514
515
	// Initialisation du tableau des descriptions et des id d'objet (au sens id_xxx).
516
	// Les tableaux sont toujours indexés par l'objet et l'id objet.
517
	static $descriptions = array();
518
	static $ids = array();
519
520
	// On détermine le nom du champ id de la table.
521
	include_spip('base/objets');
522
	$table_id = id_table_objet($objet);
523
524
	// On détermine l'id à utiliser.
525
	$champ_id = !empty($options['champ_id']) ? $options['champ_id'] : $table_id;
526
527
	// On détermine si on a passé l'id objet ou un autre identifiant unique de la table :
528
	if ($champ_id != $table_id) {
529
		// on a passé un identifiant différent que l'id de l'objet, on cherche si cet objet a déjà été rencontré
530
		// car dans ce cas on a déjà stocké son id objet.
531
		$index = isset($ids[$objet][$valeur_id]) ? $ids[$objet][$valeur_id] : 0;
532
	} else {
533
		$index = $valeur_id;
534
	}
535
536
	// On vérifie si l'objet demandé n'est pas déjà stocké : si oui, la description sera utilisée sauf si on a forcé
537
	// la lecture en base.
538
	if (isset($descriptions[$objet][$index])) {
539
		$description = $descriptions[$objet][$index];
540
	} else {
541
		$description = array();
542
	}
543
544
	// Si l'objet n'a pas encore été stocké, il faut récupérer sa description complète.
545
	if (!$description) {
546
		// Il est possible pour un type d'objet de fournir une fonction de lecture de tous les champs d'un objet.
547
		if (
548
			include_spip('action/editer_' . $objet)
549
			and function_exists($lire = "${objet}_lire_champs")
550
		) {
551
			$description = $lire($objet, $valeur_id, $champ_id);
552
		} else {
553
			// On récupère la table SQL à partir du type d'objet.
554
			$table = table_objet_sql($objet);
555
556
			// La condition est appliquée sur le champ désigné par l'utilisateur. Si ce champ n'est pas l'id objet
557
			// on considère qu'il est de type chaine.
558
			$where = ($champ_id != $table_id)
559
				? array("${champ_id}=" . sql_quote($valeur_id))
560
				: array("${champ_id}=" . intval($valeur_id));
561
562
			// Acquisition de tous les champs de l'objet : si l'accès SQL retourne une erreur on renvoie un tableau vide.
563
			if (!$description = sql_fetsel('*', $table, $where)) {
564
				$description = array();
565
			}
566
		}
567
568
		// On stocke systématiquement la description à l'index correspondant à l'objet et l'id objet.
569
		if (!$index) {
570
			// Première sauvegarde de l'objet qui est forcément lu via un champ qui n'est pas l'id objet.
571
			// Il faut donc stocker l'index pour un futur appel si la description est non vide.
572
			if ($description) {
573
				$index = $description[$table_id];
574
				$ids[$objet][$valeur_id] = $index;
575
			}
576
		}
577
578
		// Si l'index a bien été déterminé, on stocke la description à cet index.
579
		if ($index) {
580
			$descriptions[$objet][$index] = $description;
581
		}
582
	}
583
584
	// On ne retourne maintenant que les champs demandés.
585
	// - on détermine les informations à renvoyer.
586
	$informations = !empty($options['informations']) ? $options['informations'] : '';
587
	if ($description and $informations) {
588
		// Extraction des seules informations demandées.
589
		// -- si on demande une information unique on renvoie la valeur simple, sinon on renvoie un tableau.
590
		// -- si une information n'est pas un champ valide elle n'est pas renvoyée sans renvoyer d'erreur.
591
		if (is_array($informations)) {
592
			if (count($informations) == 1) {
593
				// Tableau d'une seule information : on revient à une chaine unique.
594
				$informations = array_shift($informations);
595
			} else {
596
				// Tableau des informations valides
597
				$description = array_intersect_key($description, array_flip($informations));
598
			}
599
		}
600
601
		if (is_string($informations)) {
602
			// Valeur unique demandée.
603
			$description = isset($description[$informations]) ? $description[$informations] : '';
604
		}
605
	}
606
607
	return $description;
608
}
609