Completed
Push — master ( 78c36e...23dea2 )
by cam
04:30
created

rubriques.php ➔ calculer_rubriques_if()   F

Complexity

Conditions 20
Paths 288

Size

Total Lines 60

Duplication

Lines 14
Ratio 23.33 %

Importance

Changes 0
Metric Value
cc 20
nc 288
nop 4
dl 14
loc 60
rs 2.2333
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, Système de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright © avec tendresse depuis 2001                                 *
7
 *  Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James  *
8
 *                                                                         *
9
 *  Ce programme est un logiciel libre distribué sous licence GNU/GPL.     *
10
 *  Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne.   *
11
\***************************************************************************/
12
13
/**
14
 * Fichier gérant l'actualisation et le suivi des rubriques, et de leurs branches
15
 *
16
 * @package SPIP\Core\Rubriques
17
 */
18
19
if (!defined('_ECRIRE_INC_VERSION')) {
20
	return;
21
}
22
23
24
/**
25
 * Recalcule les statuts d'une rubrique
26
 *
27
 * Fonction à appeler lorsque le statut d'un objet change dans une rubrique
28
 * ou que la rubrique est deplacée.
29
 *
30
 * Si le statut passe a "publie", la rubrique et ses parents y passent aussi
31
 * et les langues utilisees sont recalculées.
32
 * Conséquences symétriques s'il est depublié.
33
 *
34
 * S'il est deplacé alors qu'il était publiée, double conséquence.
35
 *
36
 * Tout cela devrait passer en SQL, sous forme de Cascade SQL.
37
 *
38
 * @uses depublier_branche_rubrique_if()
39
 * @uses calculer_prochain_postdate()
40
 * @uses publier_branche_rubrique()
41
 *
42
 * @param int $id_rubrique
43
 *     Identifiant de la rubrique
44
 * @param array $modifs
45
 *     Tableau de description des modifications.
46
 *     Peut avoir 2 index, 'statut' étant obligatoire :
47
 *     - statut : indique le nouveau statut de la rubrique
48
 *     - id_rubrique : indiquer la rubrique dans laquelle on déplace la rubrique (son nouveau parent donc)
49
 * @param array $infos
50
 *     Infos sur l'objet modifié : statut_ancien, objet, id_objet…
51
 * @param bool $postdate
52
 *     true pour recalculer aussi la date du prochain article post-daté
53
 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

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...
54
 *     true si le statut change effectivement
55
 **/
56
function calculer_rubriques_if($id_rubrique, $modifs, $infos = array(), $postdate = false) {
57
	$neuf = false;
58
	
59
	// Compat avec l'ancienne signature
60
	if (is_string($infos)) {
61
		$infos = array('statut_ancien' => $infos);
62
	}
63
	if (!isset($infos['statut_ancien'])) {
64
		$infos['statut_ancien'] = '';
65
	}
66
	
67
	// On recherche quels statuts tester
68
	if (
69
		isset($infos['objet'])
70
		and include_spip('inc/filtres')
71
		and $declaration_statut = objet_info($infos['objet'], 'statut')
72
		and is_array($declaration_statut)
73
	) {
74
		foreach ($declaration_statut as $champ_statut) {
75
			if ($champ_statut['champ'] == 'statut') {
76
				$statuts_publies = array_map('trim', explode(',', $champ_statut['publie']));
77
				break; // stop on a trouvé le bon champ
78
			}
79
		}
80
	}
81
	else {
82
		$statuts_publies = array('publie');
83
	}
84
	
85
	if (in_array($infos['statut_ancien'], $statuts_publies)) {
86
		if (isset($modifs['statut'])
87
			or isset($modifs['id_rubrique'])
88
			or ($postdate and strtotime($postdate) > time())
89
		) {
90
			$neuf |= depublier_branche_rubrique_if($id_rubrique);
91
		}
92
		// ne publier que si c'est pas un postdate, ou si la date n'est pas dans le futur
93 View Code Duplication
		if ($postdate) {
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...
94
			calculer_prochain_postdate(true);
95
			$neuf |= (strtotime($postdate) <= time()); // par securite
96
		} elseif (isset($modifs['id_rubrique'])) {
97
			$neuf |= publier_branche_rubrique($modifs['id_rubrique']);
98
		}
99 View Code Duplication
	} elseif (isset($modifs['statut']) and in_array($modifs['statut'], $statuts_publies)) {
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...
Bug introduced by
The variable $statuts_publies does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
100
		if ($postdate) {
101
			calculer_prochain_postdate(true);
102
			$neuf |= (strtotime($postdate) <= time()); // par securite
103
		} else {
104
			$neuf |= publier_branche_rubrique($id_rubrique);
105
		}
106
	}
107
108
	if ($neuf) // Sauver la date de la derniere mise a jour (pour menu_rubriques)
109
	{
110
		ecrire_meta("date_calcul_rubriques", date("U"));
111
	}
112
113
	$langues = calculer_langues_utilisees();
114
	ecrire_meta('langues_utilisees', $langues);
115
}
116
117
118
/**
119
 * Publie une rubrique et sa hiérarchie de rubriques
120
 *
121
 * Fonction à appeler lorsqu'on dépublie ou supprime quelque chose
122
 * dans une rubrique.
123
 *
124
 * @todo Le nom de la fonction est trompeur, vu que la fonction remonte dans la hierarchie !
125
 *
126
 * @param int $id_rubrique
127
 *     Identifiant de la rubrique
128
 * @return bool
129
 *     true si le statut change effectivement
130
 */
131
function publier_branche_rubrique($id_rubrique) {
132
	$id_pred = $id_rubrique;
133
	while (true) {
134
		sql_updateq('spip_rubriques', array('statut' => 'publie', 'date' => date('Y-m-d H:i:s')),
135
			"id_rubrique=" . intval($id_rubrique));
136
		$id_parent = sql_getfetsel('id_parent', 'spip_rubriques AS R', "R.id_rubrique=" . intval($id_rubrique));
137
		if (!$id_parent) {
138
			break;
139
		}
140
		$id_rubrique = $id_parent;
141
	}
142
143
#	spip_log(" publier_branche_rubrique($id_rubrique $id_pred");
144
	return $id_pred != $id_rubrique;
145
}
146
147
/**
148
 * Dépublie si nécessaire des éléments d'une hiérarchie de rubriques
149
 *
150
 * Fonction à appeler lorsqu'on dépublie ou supprime quelque chose
151
 * dans une rubrique.
152
 *
153
 * @uses depublier_rubrique_if()
154
 * @todo Le nom de la fonction est trompeur, vu que la fonction remonte dans la hierarchie !
155
 *
156
 * @param int $id_rubrique
157
 *     Identifiant de la rubrique
158
 * @return bool
159
 *     true si le statut change effectivement
160
 */
161
function depublier_branche_rubrique_if($id_rubrique) {
162
	$date = date('Y-m-d H:i:s'); // figer la date
163
164
	#	spip_log("depublier_branche_rubrique($id_rubrique ?");
165
	$id_pred = $id_rubrique;
166
	while ($id_pred) {
167
168
		if (!depublier_rubrique_if($id_pred, $date)) {
169
			return $id_pred != $id_rubrique;
170
		}
171
		// passer au parent si on a depublie
172
		$r = sql_fetsel("id_parent", "spip_rubriques", "id_rubrique=" . intval($id_pred));
173
		$id_pred = $r['id_parent'];
174
	}
175
176
	return $id_pred != $id_rubrique;
177
}
178
179
/**
180
 * Dépublier une rubrique si aucun contenu publié connu n'est trouvé dedans
181
 *
182
 * @pipeline_appel objet_compte_enfants
183
 *
184
 * @param int $id_rubrique
185
 *     Identifiant de la rubrique à tester
186
 * @param string|null $date
187
 *     Date pour le calcul des éléments post-datés.
188
 *     null = date actuelle.
189
 * @return bool
190
 *    true si la rubrique a été dépubliée
191
 */
192
function depublier_rubrique_if($id_rubrique, $date = null) {
193
	if (is_null($date)) {
194
		$date = date('Y-m-d H:i:s');
195
	}
196
	$postdates = ($GLOBALS['meta']["post_dates"] == "non") ?
197
		" AND date <= " . sql_quote($date) : '';
198
199
	if (!$id_rubrique = intval($id_rubrique)) {
200
		return false;
201
	}
202
203
	// verifier qu'elle existe et est bien publiee
204
	$r = sql_fetsel('id_rubrique,statut', 'spip_rubriques', "id_rubrique=" . intval($id_rubrique));
205
	if (!$r or $r['statut'] !== 'publie') {
206
		return false;
207
	}
208
209
	// On met le nombre de chaque type d'enfants dans un tableau
210
	// Le type de l'objet est au pluriel
211
	$compte = array(
212
		'articles' => sql_countsel("spip_articles",
213
			"id_rubrique=" . intval($id_rubrique) . " AND statut='publie'$postdates"),
214
		'rubriques' => sql_countsel("spip_rubriques", "id_parent=" . intval($id_rubrique) . " AND statut='publie'"),
215
		'documents' => sql_countsel(
216
			"spip_documents AS D JOIN spip_documents_liens AS L ON D.id_document=L.id_document", 
217
			"L.id_objet=" . intval($id_rubrique) . " AND L.objet='rubrique' and D.mode NOT IN('logoon', 'logooff') ")
218
	);
219
220
	// On passe le tableau des comptes dans un pipeline pour que les plugins puissent ajouter (ou retirer) des enfants
221
	$compte = pipeline('objet_compte_enfants',
222
		array(
223
			'args' => array(
224
				'objet' => 'rubrique',
225
				'id_objet' => $id_rubrique,
226
				'statut' => 'publie',
227
				'date' => $date
228
			),
229
			'data' => $compte
230
		)
231
	);
232
233
	// S'il y a au moins un enfant de n'importe quoi, on ne dépublie pas
234
	foreach ($compte as $objet => $n) {
235
		if ($n) {
236
			return false;
237
		}
238
	}
239
240
	sql_updateq("spip_rubriques", array("statut" => 'prepa'), "id_rubrique=" . intval($id_rubrique));
241
242
#		spip_log("depublier_rubrique $id_pred");
243
	return true;
244
}
245
246
247
/**
248
 * Recalcule des héritages de rubriques
249
 *
250
 * Recalcule le statut des rubriques, les langues héritées et la date
251
 * du prochain article post-daté
252
 *
253
 * Cette fonction est appelée après importation: elle calcule les meta-donnes
254
 * resultantes et remet de la coherence au cas où la base importée en manquait
255
 *
256
 * Cette fonction doit etre invoquée sans processus concurrent potentiel.
257
 *
258
 * @uses calculer_rubriques_publiees()
259
 * @uses calculer_langues_utilisees()
260
 * @uses calculer_prochain_postdate()
261
 *
262
 * @return void
263
 **/
264
function calculer_rubriques() {
265
266
	calculer_rubriques_publiees();
267
268
	// Apres chaque (de)publication 
269
	// recalculer les langues utilisees sur le site
270
	$langues = calculer_langues_utilisees();
271
	ecrire_meta('langues_utilisees', $langues);
272
273
	// Sauver la date de la derniere mise a jour (pour menu_rubriques)
274
	ecrire_meta("date_calcul_rubriques", date("U"));
275
276
	// on calcule la date du prochain article post-date
277
	calculer_prochain_postdate();
278
}
279
280
281
/**
282
 * Recalcule l'ensemble des données associées à l'arborescence des rubriques
283
 *
284
 * Attention, faute de SQL transactionnel on travaille sur
285
 * des champs temporaires afin de ne pas casser la base
286
 * pendant la demi seconde de recalculs
287
 *
288
 * @pipeline_appel calculer_rubriques
289
 *
290
 * @return void
291
 **/
292
function calculer_rubriques_publiees() {
293
294
	// Mettre les compteurs a zero
295
	sql_updateq('spip_rubriques', array('date_tmp' => '0000-00-00 00:00:00', 'statut_tmp' => 'prepa'));
296
297
	//
298
	// Publier et dater les rubriques qui ont un article publie
299
	//
300
301
	// Afficher les articles post-dates ?
302
	$postdates = ($GLOBALS['meta']["post_dates"] == "non") ?
303
		"AND A.date <= " . sql_quote(date('Y-m-d H:i:s')) : '';
304
305
	$r = sql_select(
306
		"R.id_rubrique AS id, max(A.date) AS date_h",
307
		"spip_rubriques AS R JOIN spip_articles AS A ON R.id_rubrique = A.id_rubrique",
308
		"A.date>R.date_tmp AND A.statut='publie' $postdates ", "R.id_rubrique");
309 View Code Duplication
	while ($row = sql_fetch($r)) {
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...
310
		sql_updateq("spip_rubriques", array("statut_tmp" => 'publie', "date_tmp" => $row['date_h']),
311
			"id_rubrique=" . intval($row['id']));
312
	}
313
314
	// point d'entree pour permettre a des plugins de gerer le statut
315
	// autrement (par ex: toute rubrique est publiee des sa creation)
316
	// Ce pipeline fait ce qu'il veut, mais s'il touche aux statuts/dates
317
	// c'est statut_tmp/date_tmp qu'il doit modifier
318
	// [C'est un trigger... a renommer en trig_calculer_rubriques ?]
319
	pipeline('calculer_rubriques', null);
320
321
322
	// Les rubriques qui ont une rubrique fille plus recente
323
	// on tourne tant que les donnees remontent vers la racine.
324
	do {
325
		$continuer = false;
326
		$r = sql_select(
327
			"R.id_rubrique AS id, max(SR.date_tmp) AS date_h",
328
			"spip_rubriques AS R JOIN spip_rubriques AS SR ON R.id_rubrique = SR.id_parent",
329
			"(SR.date_tmp>R.date_tmp OR R.statut_tmp<>'publie') AND SR.statut_tmp='publie' ", "R.id_rubrique");
330 View Code Duplication
		while ($row = sql_fetch($r)) {
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...
331
			sql_updateq('spip_rubriques', array('statut_tmp' => 'publie', 'date_tmp' => $row['date_h']),
332
				"id_rubrique=" . intval($row['id']));
333
			$continuer = true;
334
		}
335
	} while ($continuer);
336
337
	// Enregistrement des modifs
338
	sql_update('spip_rubriques', array('date' => 'date_tmp', 'statut' => 'statut_tmp'));
339
}
340
341
/**
342
 * Recalcule les secteurs et les profondeurs des rubriques (et articles)
343
 *
344
 * Cherche les rubriques ayant des id_secteur ou profondeurs ne correspondant pas
345
 * avec leur parent, et les met à jour. De même avec les articles et leur id_secteur
346
 * On procede en iterant la profondeur de 1 en 1 pour ne pas risquer une boucle infinie sur reference circulaire
347
 *
348
 * @pipeline_appel trig_propager_les_secteurs
349
 *
350
 * @return void
351
 **/
352
function propager_les_secteurs() {
353
	// Profondeur 0
354
	// Toutes les rubriques racines sont de profondeur 0
355
	// et fixer les id_secteur des rubriques racines
356
	sql_update('spip_rubriques', array('id_secteur' => 'id_rubrique', 'profondeur' => 0), "id_parent=0");
357
	// Toute rubrique non racine est de profondeur >0
358
	sql_updateq('spip_rubriques', array('profondeur' => 1), "id_parent<>0 AND profondeur=0");
359
360
	// securite : pas plus d'iteration que de rubriques dans la base
361
	$maxiter = sql_countsel("spip_rubriques");
362
363
	// reparer les rubriques qui n'ont pas l'id_secteur de leur parent
364
	// on fait profondeur par profondeur
365
366
	$prof = 0;
367
	do {
368
		$continuer = false;
369
370
		// Par recursivite : si toutes les rubriques de profondeur $prof sont bonnes
371
		// on fixe le profondeur $prof+1
372
373
		// Toutes les rubriques dont le parent est de profondeur $prof ont une profondeur $prof+1
374
		// on teste A.profondeur > $prof+1 car :
375
		// - toutes les rubriques de profondeur 0 à $prof sont bonnes
376
		// - si A.profondeur = $prof+1 c'est bon
377
		// - cela nous protege de la boucle infinie en cas de reference circulaire dans les rubriques
378
		$maxiter2 = $maxiter;
379
		while ($maxiter2--
380
			and $rows = sql_allfetsel(
381
				"A.id_rubrique AS id, R.id_secteur AS id_secteur, R.profondeur+1 as profondeur",
382
				"spip_rubriques AS A JOIN spip_rubriques AS R ON A.id_parent = R.id_rubrique",
383
				"R.profondeur=" . intval($prof) . " AND (A.id_secteur <> R.id_secteur OR A.profondeur > R.profondeur+1)",
384
				"", "R.id_secteur", "0,100")) {
385
386
			$id_secteur = null;
387
			$ids = array();
388
			while ($row = array_shift($rows)) {
389
				if ($row['id_secteur'] !== $id_secteur) {
390 View Code Duplication
					if (count($ids)) {
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...
391
						sql_updateq("spip_rubriques", array("id_secteur" => $id_secteur, 'profondeur' => $prof + 1),
392
							sql_in('id_rubrique', $ids));
393
					}
394
					$id_secteur = $row['id_secteur'];
395
					$ids = array();
396
				}
397
				$ids[] = $row['id'];
398
			}
399 View Code Duplication
			if (count($ids)) {
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...
400
				sql_updateq("spip_rubriques", array("id_secteur" => $id_secteur, 'profondeur' => $prof + 1),
401
					sql_in('id_rubrique', $ids));
402
			}
403
		}
404
405
406
		// Toutes les rubriques de profondeur $prof+1 qui n'ont pas un parent de profondeur $prof sont decalees
407
		$maxiter2 = $maxiter;
408
		while ($maxiter2--
409
			and $rows = sql_allfetsel(
410
				"id_rubrique as id",
411
				"spip_rubriques",
412
				"profondeur=" . intval($prof + 1) . " AND id_parent NOT IN (" . sql_get_select("zzz.id_rubrique",
413
					"spip_rubriques AS zzz", "zzz.profondeur=" . intval($prof)) . ")", '', '', '0,100')) {
414
			$rows = array_column($rows, 'id');
415
			sql_updateq("spip_rubriques", array('profondeur' => $prof + 2), sql_in("id_rubrique", $rows));
416
		}
417
418
		// ici on a fini de valider $prof+1, toutes les rubriques de prondeur 0 a $prof+1 sont OK
419
		// si pas de rubrique a profondeur $prof+1 pas la peine de continuer
420
		// si il reste des rubriques non vues, c'est une branche morte ou reference circulaire (base foireuse)
421
		// on arrete les frais
422
		if (sql_countsel("spip_rubriques", "profondeur=" . intval($prof + 1))) {
423
			$prof++;
424
			$continuer = true;
425
		}
426
	} while ($continuer and $maxiter--);
427
428
	// loger si la table des rubriques semble foireuse
429
	// et mettre un id_secteur=0 sur ces rubriques pour eviter toute selection par les boucles
430
	if (sql_countsel("spip_rubriques", "profondeur>" . intval($prof + 1))) {
431
		spip_log("Les rubriques de profondeur>" . ($prof + 1) . " semblent suspectes (branches morte ou reference circulaire dans les parents)",
432
			_LOG_CRITIQUE);
433
		sql_update("spip_rubriques", array('id_secteur' => 0), "profondeur>" . intval($prof + 1));
434
	}
435
436
	// reparer les articles
437
	$r = sql_select("A.id_article AS id, R.id_secteur AS secteur", "spip_articles AS A, spip_rubriques AS R",
438
		"A.id_rubrique = R.id_rubrique AND A.id_secteur <> R.id_secteur");
439
440
	while ($row = sql_fetch($r)) {
441
		sql_update("spip_articles", array("id_secteur" => $row['secteur']), "id_article=" . intval($row['id']));
442
	}
443
444
	// avertir les plugins qui peuvent faire leur mises a jour egalement
445
	pipeline('trig_propager_les_secteurs', '');
446
}
447
448
449
/**
450
 * Recalcule les langues héritées des sous-rubriques
451
 *
452
 * Cherche les langues incorrectes de sous rubriques, qui doivent hériter
453
 * de la rubrique parente lorsque langue_choisie est différent de oui,
454
 * et les corrige.
455
 *
456
 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|string?

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...
457
 *     true si un changement a eu lieu
458
 **/
459
function calculer_langues_rubriques_etape() {
460
	$s = sql_select("A.id_rubrique AS id_rubrique, R.lang AS lang", "spip_rubriques AS A, spip_rubriques AS R",
461
		"A.id_parent = R.id_rubrique AND A.langue_choisie != 'oui' AND R.lang<>'' AND R.lang<>A.lang");
462
463
	$t = false;
464 View Code Duplication
	while ($row = sql_fetch($s)) {
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...
465
		$id_rubrique = $row['id_rubrique'];
466
		$t = sql_updateq('spip_rubriques', array('lang' => $row['lang'], 'langue_choisie' => 'non'),
467
			"id_rubrique=" . intval($id_rubrique));
468
	}
469
470
	return $t;
471
}
472
473
/**
474
 * Recalcule les langues des rubriques et articles
475
 *
476
 * Redéfinit la langue du site sur les rubriques sans langue spécifiée
477
 * (langue_choisie différent de 'oui')
478
 *
479
 * Redéfinit les langues des articles sans langue spécifiée
480
 * (langue_choisie différent de 'oui') en les rebasant sur la langue
481
 * de la rubrique parente lorsque ce n'est pas le cas.
482
 *
483
 * @uses calculer_langues_rubriques_etape()
484
 * @pipeline_appel trig_calculer_langues_rubriques
485
 *
486
 * @return void
487
 **/
488
function calculer_langues_rubriques() {
489
490
	// rubriques (recursivite)
491
	sql_updateq("spip_rubriques", array("lang" => $GLOBALS['meta']['langue_site'], "langue_choisie" => 'non'),
492
		"id_parent=0 AND langue_choisie != 'oui'");
493
	while (calculer_langues_rubriques_etape()) {
494
		;
495
	}
496
497
	// articles
498
	$s = sql_select("A.id_article AS id_article, R.lang AS lang", "spip_articles AS A, spip_rubriques AS R",
499
		"A.id_rubrique = R.id_rubrique AND A.langue_choisie != 'oui' AND (length(A.lang)=0 OR length(R.lang)>0) AND R.lang<>A.lang");
500 View Code Duplication
	while ($row = sql_fetch($s)) {
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...
501
		$id_article = $row['id_article'];
502
		sql_updateq('spip_articles', array("lang" => $row['lang'], 'langue_choisie' => 'non'),
503
			"id_article=" . intval($id_article));
504
	}
505
506
	if ($GLOBALS['meta']['multi_rubriques'] == 'oui') {
507
508
		$langues = calculer_langues_utilisees();
509
		ecrire_meta('langues_utilisees', $langues);
510
	}
511
512
	// avertir les plugins qui peuvent faire leur mises a jour egalement
513
	pipeline('trig_calculer_langues_rubriques', '');
514
}
515
516
517
/**
518
 * Calcule la liste des langues réellement utilisées dans le site public
519
 *
520
 * La recherche de langue est effectuée en recréant une boucle pour chaque
521
 * objet éditorial gérant des langues de sorte que les éléments non publiés
522
 * ne sont pas pris en compte.
523
 *
524
 * @param string $serveur
525
 *    Nom du connecteur à la base de données
526
 * @return string
527
 *    Liste des langues utilisées séparées par des virgules
528
 **/
529
function calculer_langues_utilisees($serveur = '') {
530
	include_spip('public/interfaces');
531
	include_spip('public/compiler');
532
	include_spip('public/composer');
533
	include_spip('public/phraser_html');
534
	$langues = array();
535
536
	$langues[$GLOBALS['meta']['langue_site']] = 1;
537
538
	include_spip('base/objets');
539
	$tables = lister_tables_objets_sql();
540
	$trouver_table = charger_fonction('trouver_table', 'base');
541
542
	foreach (array_keys($tables) as $t) {
543
		$desc = $trouver_table($t, $serveur);
544
		// c'est une table avec des langues
545
		if ($desc['exist']
546
			and isset($desc['field']['lang'])
547
			and isset($desc['field']['langue_choisie'])
548
		) {
549
550
			$boucle = new Boucle();
551
			$boucle->show = $desc;
552
			$boucle->nom = 'calculer_langues_utilisees';
0 ignored issues
show
Bug introduced by
The property nom does not seem to exist in Boucle.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
553
			$boucle->id_boucle = $desc['table_objet'];
554
			$boucle->id_table = $desc['table_objet'];
555
			$boucle->sql_serveur = $serveur;
556
			$boucle->select[] = "DISTINCT lang";
557
			$boucle->from[$desc['table_objet']] = $t;
558
			$boucle->separateur[] = ',';
559
			$boucle->return = '$Pile[$SP][\'lang\']';
560
			$boucle->iterateur = 'sql';
561
562
			$boucle->descr['nom'] = 'objet_test_si_publie'; // eviter notice php
563
			$boucle->descr['sourcefile'] = 'internal';
564
565
			$boucle = pipeline('pre_boucle', $boucle);
566
567
			if (isset($desc['statut'])
568
				and $desc['statut']
569
			) {
570
				$boucles = array(
571
					'calculer_langues_utilisees' => $boucle,
572
				);
573
				// generer un nom de fonction "anonyme" unique
574
				do {
575
					$functionname = 'f_calculer_langues_utilisees_' . $boucle->id_table . '_' . time() . '_' . rand();
576
				} while (function_exists($functionname));
577
				$code = calculer_boucle('calculer_langues_utilisees', $boucles);
578
				$code = '$SP=0; $command=array();$command["connect"] = $connect = "' . $serveur . '"; $Pile=array(0=>array());' . "\n" . $code;
579
				$code = 'function ' . $functionname . '(){' . $code . '};$res = ' . $functionname . '();';
580
				$res = '';
581
				eval($code);
582
				$res = explode(',', $res);
583
				foreach ($res as $lang) {
584
					$langues[$lang] = 1;
585
				}
586
			} else {
587
				$res = sql_select(implode(',', $boucle->select), $boucle->from);
588
				while ($row = sql_fetch($res)) {
589
					$langues[$row['lang']] = 1;
590
				}
591
			}
592
		}
593
	}
594
595
	$langues = array_filter(array_keys($langues));
596
	sort($langues);
597
	$langues = join(',', $langues);
598
	spip_log("langues utilisees: $langues");
599
600
	return $langues;
601
}
602
603
/**
604
 * Calcule une branche de rubriques
605
 *
606
 * Dépréciée, pour compatibilité
607
 *
608
 * @deprecated
609
 * @see calcul_branche_in()
610
 *
611
 * @param string|int|array $generation
612
 * @return string
613
 */
614
function calcul_branche($generation) { return calcul_branche_in($generation); }
615
616
/**
617
 * Calcul d'une branche de rubrique
618
 *
619
 * Liste des id_rubrique contenues dans une rubrique donnée
620
 *
621
 * @see inc_calcul_branche_in_dist()
622
 *
623
 * @param string|int|array $id
624
 *     Identifiant de la, ou des rubriques noeuds
625
 * @return string
626
 *     Liste des identifiants séparés par des virgules,
627
 *     incluant les rubriques noeuds et toutes leurs descendances
628
 */
629
function calcul_branche_in($id) {
630
	$calcul_branche_in = charger_fonction('calcul_branche_in', 'inc');
631
632
	return $calcul_branche_in($id);
633
}
634
635
/**
636
 * Calcul d'une hiérarchie
637
 *
638
 * Liste des id_rubrique contenant une rubrique donnée
639
 *
640
 * @see inc_calcul_hierarchie_in_dist()
641
 * @param string|int|array $id
642
 *     Identifiant de la, ou des rubriques dont on veut obtenir les hierarchies
643
 * @param bool $tout
644
 *     inclure la rubrique de depart dans la hierarchie ou non
645
 * @return string
646
 *     Liste des identifiants séparés par des virgules,
647
 *     incluant les rubriques transmises et toutes leurs parentées
648
 */
649
function calcul_hierarchie_in($id, $tout = true) {
650
	$calcul_hierarchie_in = charger_fonction('calcul_hierarchie_in', 'inc');
651
652
	return $calcul_hierarchie_in($id, $tout);
653
}
654
655
656
/**
657
 * Calcul d'une branche de rubriques
658
 *
659
 * Liste des id_rubrique contenues dans une rubrique donnée
660
 * pour le critere {branche}
661
 *
662
 * Fonction surchargeable pour optimisation
663
 *
664
 * @see inc_calcul_hierarchie_in_dist() pour la hierarchie
665
 *
666
 * @param string|int|array $id
667
 *     Identifiant de la, ou des rubriques noeuds
668
 * @return string
669
 *     Liste des identifiants séparés par des virgules,
670
 *     incluant les rubriques noeuds et toutes leurs descendances
671
 */
672
function inc_calcul_branche_in_dist($id) {
673
	static $b = array();
674
675
	// normaliser $id qui a pu arriver comme un array, comme un entier, ou comme une chaine NN,NN,NN
676
	if (!is_array($id)) {
677
		$id = explode(',', $id);
678
	}
679
	$id = join(',', array_map('intval', $id));
680
	if (isset($b[$id])) {
681
		return $b[$id];
682
	}
683
684
	// Notre branche commence par la rubrique de depart
685
	$branche = $r = $id;
686
687
	// On ajoute une generation (les filles de la generation precedente)
688
	// jusqu'a epuisement, en se protegeant des references circulaires
689
	$maxiter = 10000;
690
	while ($maxiter-- and $filles = sql_allfetsel(
691
			'id_rubrique',
692
			'spip_rubriques',
693
			sql_in('id_parent', $r) . " AND " . sql_in('id_rubrique', $r, 'NOT')
694
		)) {
695
		$r = join(',', array_column($filles, 'id_rubrique'));
696
		$branche .= ',' . $r;
697
	}
698
699
	# securite pour ne pas plomber la conso memoire sur les sites prolifiques
700
	if (strlen($branche) < 10000) {
701
		$b[$id] = $branche;
702
	}
703
704
	return $branche;
705
}
706
707
708
/**
709
 * Calcul d'une hiérarchie
710
 *
711
 * Liste des id_rubrique contenant une rubrique donnée,
712
 * contrairement à la fonction calcul_branche_in() qui calcule les
713
 * rubriques contenues
714
 *
715
 * @see inc_calcul_branche_in_dist() pour la descendence
716
 *
717
 * @param string|int|array $id
718
 *     Identifiant de la, ou des rubriques dont on veut obtenir les hierarchies
719
 * @param bool $tout
720
 *     inclure la rubrique de depart dans la hierarchie ou non
721
 * @return string
722
 *     Liste des identifiants séparés par des virgules,
723
 *     incluant les rubriques transmises et toutes leurs parentées
724
 */
725
function inc_calcul_hierarchie_in_dist($id, $tout = true) {
726
	static $b = array();
727
728
	// normaliser $id qui a pu arriver comme un array, comme un entier, ou comme une chaine NN,NN,NN
729
	if (!is_array($id)) {
730
		$id = explode(',', $id);
731
	}
732
	$id = join(',', array_map('intval', $id));
733
734
	if (isset($b[$id])) {
735
		// Notre branche commence par la rubrique de depart si $tout=true
736
		return $tout ? (strlen($b[$id]) ? $b[$id] . ",$id" : $id) : $b[$id];
737
	}
738
739
	$hier = "";
740
741
	// On ajoute une generation (les filles de la generation precedente)
742
	// jusqu'a epuisement, en se protegeant des references circulaires
743
	$ids_nouveaux_parents = $id;
744
	$maxiter = 10000;
745
	while ($maxiter-- and $parents = sql_allfetsel(
746
			'id_parent',
747
			'spip_rubriques',
748
			sql_in('id_rubrique', $ids_nouveaux_parents) . " AND " . sql_in('id_parent', $hier, 'NOT')
749
		)) {
750
		$ids_nouveaux_parents = join(',', array_column($parents, 'id_parent'));
751
		$hier = $ids_nouveaux_parents . (strlen($hier) ? ',' . $hier : '');
752
	}
753
754
	# securite pour ne pas plomber la conso memoire sur les sites prolifiques
755
	if (strlen($hier) < 10000) {
756
		$b[$id] = $hier;
757
	}
758
759
	// Notre branche commence par la rubrique de depart si $tout=true
760
	$hier = $tout ? (strlen($hier) ? "$hier,$id" : $id) : $hier;
761
762
	return $hier;
763
}
764
765
766
/**
767
 * Calcule la date du prochain article post-daté
768
 *
769
 * Appelée lorsqu'un (ou plusieurs) article post-daté arrive à terme
770
 * ou est redaté
771
 *
772
 * @uses publier_branche_rubrique()
773
 * @pipeline_appel trig_calculer_prochain_postdate
774
 *
775
 * @param bool $check
776
 *     true pour affecter le statut des rubriques concernées.
777
 * @return void
778
 **/
779
function calculer_prochain_postdate($check = false) {
780
	include_spip('base/abstract_sql');
781
	if ($check) {
782
		$postdates = ($GLOBALS['meta']["post_dates"] == "non") ?
783
			"AND A.date <= " . sql_quote(date('Y-m-d H:i:s')) : '';
784
785
		$r = sql_select("DISTINCT A.id_rubrique AS id",
786
			"spip_articles AS A LEFT JOIN spip_rubriques AS R ON A.id_rubrique=R.id_rubrique",
787
			"R.statut != 'publie' AND A.statut='publie'$postdates");
788
		while ($row = sql_fetch($r)) {
789
			publier_branche_rubrique($row['id']);
790
		}
791
792
		pipeline('trig_calculer_prochain_postdate', '');
793
	}
794
795
	$t = sql_fetsel("date", "spip_articles", "statut='publie' AND date > " . sql_quote(date('Y-m-d H:i:s')), "", "date",
796
		"1");
797
798
	if ($t) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $t 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...
799
		$t = $t['date'];
800
		if (!isset($GLOBALS['meta']['date_prochain_postdate'])
801
			or $t <> $GLOBALS['meta']['date_prochain_postdate']
802
		) {
803
			ecrire_meta('date_prochain_postdate', strtotime($t));
804
			ecrire_meta('derniere_modif', time());
805
		}
806
	} else {
807
		effacer_meta('date_prochain_postdate');
808
		ecrire_meta('derniere_modif', time());
809
	}
810
811
	spip_log("prochain postdate: $t");
812
}
813
814
/**
815
 * Crée une arborescence de rubrique
816
 *
817
 * creer_rubrique_nommee('truc/machin/chose') va créer
818
 * une rubrique truc, une sous-rubrique machin, et une sous-sous-rubrique
819
 * chose, sans créer de rubrique si elle existe déjà
820
 * à partir de $id_parent (par défaut, à partir de la racine)
821
 *
822
 * NB: cette fonction est très pratique, mais pas utilisée dans le core
823
 * pour rester légère elle n'appelle pas calculer_rubriques()
824
 *
825
 * @param string $titre
826
 *     Titre des rubriques, séparés par des /
827
 * @param int $id_parent
828
 *     Identifiant de la rubrique parente
829
 * @param string $serveur
830
 *     Nom du connecteur à la base de données
831
 * @return int
832
 *     Identifiant de la rubrique la plus profonde.
833
 */
834
function creer_rubrique_nommee($titre, $id_parent = 0, $serveur = '') {
835
836
	// eclater l'arborescence demandee
837
	// echapper les </multi> et autres balises fermantes html
838
	$titre = preg_replace(",</([a-z][^>]*)>,ims", "<@\\1>", $titre);
839
	$arbo = explode('/', preg_replace(',^/,', '', $titre));
840
	include_spip('base/abstract_sql');
841
	foreach ($arbo as $titre) {
842
		// retablir les </multi> et autres balises fermantes html
843
		$titre = preg_replace(",<@([a-z][^>]*)>,ims", "</\\1>", $titre);
844
		$r = sql_getfetsel("id_rubrique", "spip_rubriques",
845
			"titre = " . sql_quote($titre) . " AND id_parent=" . intval($id_parent),
846
			$groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur);
847
		if ($r !== null) {
848
			$id_parent = $r;
849
		} else {
850
			$id_rubrique = sql_insertq('spip_rubriques', array(
851
					'titre' => $titre,
852
					'id_parent' => $id_parent,
853
					'statut' => 'prepa'
854
				), $desc = array(), $serveur);
855
			if ($id_parent > 0) {
856
				$data = sql_fetsel("id_secteur,lang", "spip_rubriques", "id_rubrique=$id_parent",
857
					$groupby = array(), $orderby = array(), $limit = '', $having = array(), $serveur);
858
				$id_secteur = $data['id_secteur'];
859
				$lang = $data['lang'];
860
			} else {
861
				$id_secteur = $id_rubrique;
862
				$lang = $GLOBALS['meta']['langue_site'];
863
			}
864
865
			sql_updateq('spip_rubriques', array('id_secteur' => $id_secteur, "lang" => $lang),
866
				"id_rubrique=" . intval($id_rubrique), $desc = '', $serveur);
867
868
			// pour la recursion
869
			$id_parent = $id_rubrique;
870
		}
871
	}
872
873
	return intval($id_parent);
874
}
875