
3 changed files with 910 additions and 0 deletions
@ -0,0 +1,648 @@
|
||||
<?php |
||||
|
||||
/***************************************************************************\ |
||||
* SPIP, Systeme de publication pour l'internet * |
||||
* * |
||||
* Copyright (c) 2001-2012 * |
||||
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * |
||||
* * |
||||
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. * |
||||
* Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * |
||||
\***************************************************************************/ |
||||
|
||||
/** |
||||
* API d'édition de liens |
||||
* |
||||
* @package SPIP\Liens\API |
||||
*/ |
||||
|
||||
if (!defined('_ECRIRE_INC_VERSION')) return; |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* Teste l'existence de la table de liaison xxx_liens d'un objet |
||||
* |
||||
* @api |
||||
* @param string $objet |
||||
* Objet à tester |
||||
* @return array|bool |
||||
* - false si l'objet n'est pas associable. |
||||
* - array(clé primaire, nom de la table de lien) si associable |
||||
*/ |
||||
function objet_associable($objet){ |
||||
$trouver_table = charger_fonction('trouver_table','base'); |
||||
$table_sql = table_objet_sql($objet); |
||||
|
||||
$l=""; |
||||
if ($primary = id_table_objet($objet) |
||||
AND $trouver_table($l = $table_sql."_liens") |
||||
AND !preg_match(',[^\w],',$primary) |
||||
AND !preg_match(',[^\w],',$l)) |
||||
return array($primary,$l); |
||||
|
||||
spip_log("Objet $objet non associable : ne dispose pas d'une cle primaire $primary OU d'une table liens $l"); |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Associer un ou des objets à des objets listés |
||||
* |
||||
* $objets_source et $objets_lies sont de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type |
||||
* ou de la forme array("NOT",$id_objets) pour une selection par exclusion |
||||
* |
||||
* Les objets sources sont les pivots qui portent les liens |
||||
* et pour lesquels une table spip_xxx_liens existe |
||||
* (auteurs, documents, mots) |
||||
* |
||||
* on peut passer optionnellement une qualification du (des) lien(s) qui sera |
||||
* alors appliquee dans la foulee. |
||||
* En cas de lot de liens, c'est la meme qualification qui est appliquee a tous |
||||
* |
||||
* @api |
||||
* @param array $objets_source |
||||
* @param array|string $objets_lies |
||||
* @param array $qualif |
||||
* @return bool|int |
||||
*/ |
||||
function objet_associer($objets_source, $objets_lies, $qualif = null){ |
||||
$modifs = objet_traiter_liaisons('lien_insert', $objets_source, $objets_lies); |
||||
|
||||
if ($qualif) |
||||
objet_qualifier_liens($objets_source, $objets_lies, $qualif); |
||||
|
||||
return $modifs; // pas d'erreur |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Dissocier un (ou des) objet(s) des objets listés |
||||
* |
||||
* $objets_source et $objets sont de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type |
||||
* |
||||
* Les objets sources sont les pivots qui portent les liens |
||||
* et pour lesquels une table spip_xxx_liens existe |
||||
* (auteurs, documents, mots) |
||||
* |
||||
* un * pour $objet,$id_objet permet de traiter par lot |
||||
* seul le type de l'objet source ne peut pas accepter de joker et doit etre explicite |
||||
* |
||||
* @api |
||||
* @param array $objets_source |
||||
* @param array|string $objets_lies |
||||
* @return bool|int |
||||
*/ |
||||
function objet_dissocier($objets_source,$objets_lies){ |
||||
return objet_traiter_liaisons('lien_delete',$objets_source,$objets_lies); |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* Qualifier le lien entre un (ou des) objet(s) et des objets listés |
||||
* |
||||
* $objets_source et $objets sont de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type |
||||
* |
||||
* Les objets sources sont les pivots qui portent les liens |
||||
* et pour lesquels une table spip_xxx_liens existe |
||||
* (auteurs, documents, mots) |
||||
* |
||||
* un * pour $objet,$id_objet permet de traiter par lot |
||||
* seul le type de l'objet source ne peut pas accepter de joker et doit etre explicite |
||||
* |
||||
* @api |
||||
* @param array $objets_source |
||||
* @param array|string $objets_lies |
||||
* @param array $qualif |
||||
* @return bool|int |
||||
*/ |
||||
function objet_qualifier_liens($objets_source,$objets_lies,$qualif){ |
||||
return objet_traiter_liaisons('lien_set',$objets_source,$objets_lies,$qualif); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Trouver les liens entre objets |
||||
* |
||||
* $objets_source et $objets sont de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type |
||||
* |
||||
* Les objets sources sont les pivots qui portent les liens |
||||
* et pour lesquels une table spip_xxx_liens existe |
||||
* (auteurs, documents, mots) |
||||
* |
||||
* un * pour $objet,$id_objet permet de traiter par lot |
||||
* seul le type de l'objet source ne peut pas accepter de joker et doit etre explicite |
||||
* |
||||
* renvoie une liste de tableaux decrivant chaque lien |
||||
* dans lequel objet_source et objet_lie sont aussi affectes avec l'id de chaque |
||||
* par facilite |
||||
* ex : |
||||
* array( |
||||
* array('id_document'=>23,'objet'=>'article','id_objet'=>12,'vu'=>'oui', |
||||
* 'document'=>23,'article'=>12) |
||||
* ) |
||||
* |
||||
* @api |
||||
* @param array $objets_source |
||||
* @param array|string $objets_lies |
||||
* @return array |
||||
*/ |
||||
function objet_trouver_liens($objets_source,$objets_lies){ |
||||
return objet_traiter_liaisons('lien_find',$objets_source,$objets_lies); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Nettoyer les liens morts vers des objets qui n'existent plus |
||||
* |
||||
* $objets_source et $objets sont de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type |
||||
* |
||||
* Les objets sources sont les pivots qui portent les liens |
||||
* et pour lesquels une table spip_xxx_liens existe |
||||
* (auteurs, documents, mots) |
||||
* |
||||
* un * pour $objet,$id_objet permet de traiter par lot |
||||
* seul le type de l'objet source ne peut pas accepter de joker et doit etre explicite |
||||
* |
||||
* @api |
||||
* @param array $objets_source |
||||
* @param array|string $objets_lies |
||||
* @return int |
||||
*/ |
||||
function objet_optimiser_liens($objets_source,$objets_lies){ |
||||
return objet_traiter_liaisons('lien_optimise',$objets_source,$objets_lies); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Dupliquer tous les liens entrant ou sortants d'un objet |
||||
* vers un autre (meme type d'objet, mais id different) |
||||
* |
||||
* @api |
||||
* @param string $objet |
||||
* @param int $id_source |
||||
* @param int $id_cible |
||||
* @return int |
||||
* Nombre de liens copiés |
||||
*/ |
||||
function objet_dupliquer_liens($objet,$id_source,$id_cible){ |
||||
include_spip('base/objets'); |
||||
$tables = lister_tables_objets_sql(); |
||||
$n = 0; |
||||
foreach($tables as $table_sql => $infos){ |
||||
if (objet_associable($infos['type'])){ |
||||
$liens = (($infos['type']==$objet)? |
||||
objet_trouver_liens(array($objet=>$id_source),'*') |
||||
: |
||||
objet_trouver_liens(array($infos['type']=>'*'),array($objet=>$id_source))); |
||||
foreach($liens as $lien){ |
||||
$n++; |
||||
if ($infos['type']==$objet){ |
||||
objet_associer(array($objet=>$id_cible),array($lien['objet']=>$lien[$lien['objet']]),$lien); |
||||
} |
||||
else { |
||||
objet_associer(array($infos['type']=>$lien[$infos['type']]),array($objet=>$id_cible),$lien); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return $n; |
||||
} |
||||
|
||||
/** |
||||
* Fonctions techniques |
||||
* ne pas les appeler directement |
||||
*/ |
||||
|
||||
|
||||
/** |
||||
* Fonction générique qui |
||||
* applique une operation de liaison entre un ou des objets et des objets listés |
||||
* $objets_source et $objets_lies sont de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type |
||||
* |
||||
* Les objets sources sont les pivots qui portent les liens |
||||
* et pour lesquels une table spip_xxx_liens existe |
||||
* (auteurs, documents, mots) |
||||
* |
||||
* on peut passer optionnellement une qualification du (des) lien(s) qui sera |
||||
* alors appliquee dans la foulee. |
||||
* En cas de lot de liens, c'est la meme qualification qui est appliquee a tous |
||||
* |
||||
* @internal |
||||
* @param string $operation |
||||
* @param array $objets_source |
||||
* @param array $objets_lies |
||||
* @param array $set |
||||
* @return bool|int|array |
||||
*/ |
||||
function objet_traiter_liaisons($operation,$objets_source,$objets_lies, $set = null){ |
||||
// accepter une syntaxe minimale pour supprimer tous les liens |
||||
if ($objets_lies=='*') $objets_lies = array('*'=>'*'); |
||||
$modifs = 0; // compter le nombre de modifications |
||||
$echec = null; |
||||
foreach($objets_source as $objet=>$ids){ |
||||
if ($a = objet_associable($objet)) { |
||||
list($primary,$l) = $a; |
||||
if (!is_array($ids)) |
||||
$ids = array($ids); |
||||
elseif(reset($ids)=="NOT"){ |
||||
// si on demande un array('NOT',...) => recuperer la liste d'ids correspondants |
||||
$where = lien_where($primary,$ids,'*','*'); |
||||
$ids = sql_allfetsel($primary,$l,$where); |
||||
$ids = array_map('reset',$ids); |
||||
} |
||||
foreach($ids as $id) { |
||||
$res = $operation($objet,$primary,$l,$id,$objets_lies,$set); |
||||
if ($res===false) { |
||||
spip_log("objet_traiter_liaisons [Echec] : $operation sur $objet/$primary/$l/$id",_LOG_ERREUR); |
||||
$echec = true; |
||||
} |
||||
else |
||||
$modifs=($modifs?(is_array($res)?array_merge($modifs,$res):$modifs+$res):$res); |
||||
} |
||||
} |
||||
else |
||||
$echec = true; |
||||
} |
||||
|
||||
return ($echec?false:$modifs); // pas d'erreur |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Sous fonction insertion |
||||
* qui traite les liens pour un objet source dont la clé primaire |
||||
* et la table de lien sont fournies |
||||
* |
||||
* $objets et de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* |
||||
* Retourne le nombre d'insertions realisees |
||||
* |
||||
* @internal |
||||
* @param string $objet_source |
||||
* @param string $primary |
||||
* @param sgring $table_lien |
||||
* @param int $id |
||||
* @param array $objets |
||||
* @return bool|int |
||||
*/ |
||||
function lien_insert($objet_source,$primary,$table_lien,$id,$objets) { |
||||
$ins = 0; |
||||
$echec = null; |
||||
foreach($objets as $objet => $id_objets){ |
||||
if (!is_array($id_objets)) $id_objets = array($id_objets); |
||||
foreach($id_objets as $id_objet) { |
||||
$objet = ($objet=='*')?$objet:objet_type($objet); # securite |
||||
// Envoyer aux plugins |
||||
$id_objet = pipeline('pre_edition_lien', |
||||
array( |
||||
'args' => array( |
||||
'table_lien' => $table_lien, |
||||
'objet_source' => $objet_source, |
||||
'id_objet_source' => $id, |
||||
'objet' => $objet, |
||||
'id_objet' => $id_objet, |
||||
'action'=>'insert', |
||||
), |
||||
'data' => $id_objet |
||||
) |
||||
); |
||||
if ($id_objet=intval($id_objet) |
||||
AND !sql_getfetsel( |
||||
$primary, |
||||
$table_lien, |
||||
array('id_objet='.intval($id_objet), 'objet='.sql_quote($objet), $primary.'='.intval($id)))) |
||||
{ |
||||
|
||||
$e = sql_insertq($table_lien, array('id_objet' => $id_objet, 'objet'=>$objet, $primary=>$id)); |
||||
if ($e!==false) { |
||||
$ins++; |
||||
lien_propage_date_modif($objet,$id_objet); |
||||
lien_propage_date_modif($objet_source,$id); |
||||
// Envoyer aux plugins |
||||
pipeline('post_edition_lien', |
||||
array( |
||||
'args' => array( |
||||
'table_lien' => $table_lien, |
||||
'objet_source' => $objet_source, |
||||
'id_objet_source' => $id, |
||||
'objet' => $objet, |
||||
'id_objet' => $id_objet, |
||||
'action'=>'insert', |
||||
), |
||||
'data' => $id_objet |
||||
) |
||||
); |
||||
} |
||||
else |
||||
$echec = true; |
||||
} |
||||
} |
||||
} |
||||
return ($echec?false:$ins); |
||||
} |
||||
|
||||
/** |
||||
* Fabriquer la condition where en tenant compte des jokers * |
||||
* |
||||
* @internal |
||||
* @param string $primary |
||||
* @param int|string|array $id_source |
||||
* @param string $objet |
||||
* @param int|string|array $id_objet |
||||
* @return array |
||||
*/ |
||||
function lien_where($primary, $id_source, $objet, $id_objet){ |
||||
if ((!is_array($id_source) AND !strlen($id_source)) |
||||
OR !strlen($objet) |
||||
OR (!is_array($id_objet) AND !strlen($id_objet))) |
||||
return array("0=1"); // securite |
||||
|
||||
$not=""; |
||||
if (is_array($id_source) AND reset($id_source)=="NOT"){ |
||||
$not = array_shift($id_source); |
||||
$id_source = reset($id_source); |
||||
} |
||||
$where = array(); |
||||
if ($id_source!=='*') |
||||
$where[] = (is_array($id_source)?sql_in(addslashes($primary),array_map('intval',$id_source),$not):addslashes($primary) . ($not?"<>":"=") . intval($id_source)); |
||||
elseif ($not) |
||||
$where[] = "0=1"; // idiot mais quand meme |
||||
|
||||
$not=""; |
||||
if (is_array($id_objet) AND reset($id_objet)=="NOT"){ |
||||
$not = array_shift($id_objet); |
||||
$id_objet = reset($id_objet); |
||||
} |
||||
|
||||
if ($objet!=='*') |
||||
$where[] = "objet=".sql_quote($objet); |
||||
if ($id_objet!=='*') |
||||
$where[] = (is_array($id_objet)?sql_in('id_objet',array_map('intval',$id_objet),$not):"id_objet" . ($not?"<>":"=") . intval($id_objet)); |
||||
elseif ($not) |
||||
$where[] = "0=1"; // idiot mais quand meme |
||||
|
||||
return $where; |
||||
} |
||||
|
||||
/** |
||||
* Sous fonction suppression |
||||
* qui traite les liens pour un objet source dont la clé primaire |
||||
* et la table de lien sont fournies |
||||
* |
||||
* $objets et de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* un * pour $id,$objet,$id_objets permet de traiter par lot |
||||
* |
||||
* @internal |
||||
* @param string $objet_source |
||||
* @param string $primary |
||||
* @param sgring $table_lien |
||||
* @param int $id |
||||
* @param array $objets |
||||
* @return bool|int |
||||
*/ |
||||
function lien_delete($objet_source,$primary,$table_lien,$id,$objets){ |
||||
$retire = array(); |
||||
$dels = 0; |
||||
$echec = false; |
||||
foreach($objets as $objet => $id_objets){ |
||||
$objet = ($objet=='*')?$objet:objet_type($objet); # securite |
||||
if (!is_array($id_objets) OR reset($id_objets)=="NOT") $id_objets = array($id_objets); |
||||
foreach($id_objets as $id_objet) { |
||||
// id_objet peut valoir '*' |
||||
$where = lien_where($primary, $id, $objet, $id_objet); |
||||
// lire les liens existants pour propager la date de modif |
||||
$liens = sql_allfetsel("$primary,id_objet,objet",$table_lien,$where); |
||||
// iterer sur les liens pour permettre aux plugins de gerer |
||||
foreach($liens as $l){ |
||||
// Envoyer aux plugins |
||||
$id_o = pipeline('pre_edition_lien', |
||||
array( |
||||
'args' => array( |
||||
'table_lien' => $table_lien, |
||||
'objet_source' => $objet_source, |
||||
'id_objet_source' => $l[$primary], |
||||
'objet' => $l['objet'], |
||||
'id_objet' => $l['id_objet'], |
||||
'action'=>'delete', |
||||
), |
||||
'data' => $l['id_objet'] |
||||
) |
||||
); |
||||
if ($id_o=intval($id_o)){ |
||||
$where = lien_where($primary, $l[$primary], $l['objet'], $id_o); |
||||
$e = sql_delete($table_lien, $where); |
||||
if ($e!==false){ |
||||
$dels+=$e; |
||||
lien_propage_date_modif($l['objet'],$id_o); |
||||
lien_propage_date_modif($objet_source,$l[$primary]); |
||||
} |
||||
else |
||||
$echec = true; |
||||
$retire[] = array('source'=>array($objet_source=>$l[$primary]),'lien'=>array($l['objet']=>$id_o),'type'=>$l['objet'],'id'=>$id_o); |
||||
// Envoyer aux plugins |
||||
pipeline('post_edition_lien', |
||||
array( |
||||
'args' => array( |
||||
'table_lien' => $table_lien, |
||||
'objet_source' => $objet_source, |
||||
'id_objet_source' => $l[$primary], |
||||
'objet' => $l['objet'], |
||||
'id_objet' => $id_o, |
||||
'action'=>'delete', |
||||
), |
||||
'data' => $id_o |
||||
) |
||||
); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
pipeline('trig_supprimer_objets_lies',$retire); |
||||
|
||||
return ($echec?false:$dels); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Sous fonction optimisation |
||||
* qui nettoie les liens morts (vers un objet inexistant) |
||||
* pour un objet source dont la clé primaire |
||||
* et la table de lien sont fournies |
||||
* |
||||
* $objets et de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* un * pour $id,$objet,$id_objets permet de traiter par lot |
||||
* |
||||
* @internal |
||||
* @param string $objet_source |
||||
* @param string $primary |
||||
* @param sgring $table_lien |
||||
* @param int $id |
||||
* @param array $objets |
||||
* @return bool|int |
||||
*/ |
||||
function lien_optimise($objet_source,$primary,$table_lien,$id,$objets){ |
||||
include_spip('genie/optimiser'); |
||||
$echec = false; |
||||
$dels = 0; |
||||
foreach($objets as $objet => $id_objets){ |
||||
$objet = ($objet=='*')?$objet:objet_type($objet); # securite |
||||
if (!is_array($id_objets) OR reset($id_objets)=="NOT") $id_objets = array($id_objets); |
||||
foreach($id_objets as $id_objet) { |
||||
$where = lien_where($primary, $id, $objet, $id_objet); |
||||
# les liens vers un objet inexistant |
||||
$r = sql_select("DISTINCT objet",$table_lien,$where); |
||||
while ($t = sql_fetch($r)){ |
||||
$type = $t['objet']; |
||||
$spip_table_objet = table_objet_sql($type); |
||||
$id_table_objet = id_table_objet($type); |
||||
$res = sql_select("L.$primary AS id,L.id_objet", |
||||
"$table_lien AS L |
||||
LEFT JOIN $spip_table_objet AS O |
||||
ON O.$id_table_objet=L.id_objet AND L.objet=".sql_quote($type), |
||||
"O.$id_table_objet IS NULL"); |
||||
// sur une cle primaire composee, pas d'autres solutions que de virer un a un |
||||
while ($row = sql_fetch($res)){ |
||||
$e = sql_delete($table_lien, array("$primary=".$row['id'],"id_objet=".$row['id_objet'],"objet=".sql_quote($type))); |
||||
if ($e!=false){ |
||||
$dels+=$e; |
||||
spip_log("Entree ".$row['id']."/".$row['id_objet']."/$type supprimee dans la table $table_lien"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
# les liens depuis un objet inexistant |
||||
$table_source = table_objet_sql($objet_source); |
||||
// filtrer selon $id, $objet, $id_objet eventuellement fournis |
||||
// (en general '*' pour chaque) |
||||
$where = lien_where("L.$primary", $id, $objet, $id_objet); |
||||
$where[] = "O.$primary IS NULL"; |
||||
$res = sql_select("L.$primary AS id", |
||||
"$table_lien AS L LEFT JOIN $table_source AS O ON L.$primary=O.$primary", |
||||
$where); |
||||
$dels+= optimiser_sansref($table_lien, $primary, $res); |
||||
} |
||||
} |
||||
return ($echec?false:$dels); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Sous fonction qualification |
||||
* qui traite les liens pour un objet source dont la clé primaire |
||||
* et la table de lien sont fournies |
||||
* |
||||
* $objets et de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* un * pour $id,$objet,$id_objets permet de traiter par lot |
||||
* |
||||
* exemple : |
||||
* $qualif = array('vu'=>'oui'); |
||||
* |
||||
* @internal |
||||
* @param string $objet_source |
||||
* @param string $primary |
||||
* @param sgring $table_lien |
||||
* @param int $id |
||||
* @param array $objets |
||||
* @param array $qualif |
||||
* @return bool|int |
||||
*/ |
||||
function lien_set($objet_source,$primary,$table_lien,$id,$objets,$qualif){ |
||||
$echec = null; |
||||
$ok = 0; |
||||
if (!$qualif) |
||||
return false; |
||||
// nettoyer qualif qui peut venir directement d'un objet_trouver_lien : |
||||
unset($qualif[$primary]); |
||||
unset($qualif[$objet_source]); |
||||
if (isset($qualif['objet'])) { |
||||
unset($qualif[$qualif['objet']]); |
||||
} |
||||
unset($qualif['objet']); |
||||
unset($qualif['id_objet']); |
||||
foreach($objets as $objet => $id_objets){ |
||||
$objet = ($objet=='*')?$objet:objet_type($objet); # securite |
||||
if (!is_array($id_objets) OR reset($id_objets)=="NOT") $id_objets = array($id_objets); |
||||
foreach($id_objets as $id_objet) { |
||||
$where = lien_where($primary, $id, $objet, $id_objet); |
||||
$e = sql_updateq($table_lien,$qualif,$where); |
||||
if ($e===false) |
||||
$echec = true; |
||||
else |
||||
$ok++; |
||||
} |
||||
} |
||||
return ($echec?false:$ok); |
||||
} |
||||
|
||||
/** |
||||
* Sous fonction trouver |
||||
* qui cherche les liens pour un objet source dont la clé primaire |
||||
* et la table de lien sont fournies |
||||
* |
||||
* $objets et de la forme |
||||
* array($objet=>$id_objets,...) |
||||
* un * pour $id,$objet,$id_objets permet de traiter par lot |
||||
* |
||||
* |
||||
* @internal |
||||
* @param string $objet_source |
||||
* @param string $primary |
||||
* @param sgring $table_lien |
||||
* @param int $id |
||||
* @param array $objets |
||||
* @return array |
||||
*/ |
||||
function lien_find($objet_source,$primary,$table_lien,$id,$objets){ |
||||
$trouve = array(); |
||||
foreach($objets as $objet => $id_objets){ |
||||
$objet = ($objet=='*')?$objet:objet_type($objet); # securite |
||||
// lien_where prend en charge les $id_objets sous forme int ou array |
||||
$where = lien_where($primary, $id, $objet, $id_objets); |
||||
$liens = sql_allfetsel('*',$table_lien,$where); |
||||
// ajouter les entrees objet_source et objet cible par convenance |
||||
foreach($liens as $l) { |
||||
$l[$objet_source] = $l[$primary]; |
||||
$l[$objet] = $l['id_objet']; |
||||
$trouve[] = $l; |
||||
} |
||||
} |
||||
return $trouve; |
||||
} |
||||
|
||||
/** |
||||
* Propager la date_modif sur les objets dont un lien a été modifié |
||||
* |
||||
* @internal |
||||
* @param string $objet |
||||
* @param array|int $ids |
||||
*/ |
||||
function lien_propage_date_modif($objet,$ids){ |
||||
$trouver_table = charger_fonction('trouver_table','base'); |
||||
|
||||
$table = table_objet_sql($objet); |
||||
if ($desc = $trouver_table($table) |
||||
AND isset($desc['field']['date_modif'])){ |
||||
$primary = id_table_objet($objet); |
||||
$where = (is_array($ids)?sql_in($primary, array_map('intval',$ids)):"$primary=".intval($ids)); |
||||
sql_updateq($table, array('date_modif'=>date('Y-m-d H:i:s')), $where); |
||||
} |
||||
} |
||||
?> |
@ -0,0 +1,260 @@
|
||||
<?php |
||||
|
||||
/***************************************************************************\ |
||||
* SPIP, Systeme de publication pour l'internet * |
||||
* * |
||||
* Copyright (c) 2001-2012 * |
||||
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * |
||||
* * |
||||
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. * |
||||
* Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * |
||||
\***************************************************************************/ |
||||
|
||||
/** |
||||
* Gestion du formulaire d'édition de liens |
||||
* |
||||
* @package SPIP\Formulaires |
||||
**/ |
||||
if (!defined('_ECRIRE_INC_VERSION')) return; |
||||
|
||||
|
||||
/** |
||||
* Retrouve la source et l'objet de la liaison |
||||
* |
||||
* À partir des 3 premiers paramètres transmis au formulaire, |
||||
* la fonction retrouve : |
||||
* - l'objet dont on utilise sa table de liaison (table_source) |
||||
* - l'objet et id_objet sur qui on lie des éléments (objet, id_objet) |
||||
* - l'objet que l'on veut lier dessus (objet_lien) |
||||
* |
||||
* @param string $a |
||||
* @param string|int $b |
||||
* @param int|string $c |
||||
* @return array |
||||
* ($table_source,$objet,$id_objet,$objet_lien) |
||||
*/ |
||||
function determine_source_lien_objet($a,$b,$c){ |
||||
$table_source = $objet_lien = $objet = $id_objet = null; |
||||
// auteurs, article, 23 : |
||||
// associer des auteurs à l'article 23, sur la table pivot spip_auteurs_liens |
||||
if (is_numeric($c) AND !is_numeric($b)){ |
||||
$table_source = table_objet($a); |
||||
$objet_lien = objet_type($a); |
||||
$objet = objet_type($b); |
||||
$id_objet = $c; |
||||
} |
||||
// article, 23, auteurs |
||||
// associer des auteurs à l'article 23, sur la table pivot spip_articles_liens |
||||
if (is_numeric($b) AND !is_numeric($c)){ |
||||
$table_source = table_objet($c); |
||||
$objet_lien = objet_type($a); |
||||
$objet = objet_type($a); |
||||
$id_objet = $b; |
||||
} |
||||
|
||||
return array($table_source,$objet,$id_objet,$objet_lien); |
||||
} |
||||
|
||||
/** |
||||
* Chargement du formulaire d'édition de liens |
||||
* |
||||
* #FORMULAIRE_EDITER_LIENS{auteurs,article,23} |
||||
* pour associer des auteurs à l'article 23, sur la table pivot spip_auteurs_liens |
||||
* #FORMULAIRE_EDITER_LIENS{article,23,auteurs} |
||||
* pour associer des auteurs à l'article 23, sur la table pivot spip_articles_liens |
||||
* #FORMULAIRE_EDITER_LIENS{articles,auteur,12} |
||||
* pour associer des articles à l'auteur 12, sur la table pivot spip_articles_liens |
||||
* #FORMULAIRE_EDITER_LIENS{auteur,12,articles} |
||||
* pour associer des articles à l'auteur 12, sur la table pivot spip_auteurs_liens |
||||
* |
||||
* @param string $a |
||||
* @param string|int $b |
||||
* @param int|string $c |
||||
* @param bool $editable |
||||
* @return array |
||||
*/ |
||||
function formulaires_editer_liens_charger_dist($a,$b,$c,$editable=true){ |
||||
|
||||
list($table_source,$objet,$id_objet,$objet_lien) = determine_source_lien_objet($a,$b,$c); |
||||
if (!$table_source OR !$objet OR !$objet_lien OR !$id_objet) |
||||
return false; |
||||
|
||||
$objet_source = objet_type($table_source); |
||||
$table_sql_source = table_objet_sql($objet_source); |
||||
|
||||
// verifier existence de la table xxx_liens |
||||
include_spip('action/editer_liens'); |
||||
if (!objet_associable($objet_lien)) |
||||
return false; |
||||
|
||||
// L'éditabilité :) est définie par un test permanent (par exemple "associermots") ET le 4ème argument |
||||
$editable = ($editable and autoriser('associer'.$table_source, $objet, $id_objet)); |
||||
|
||||
if (!$editable AND !count(objet_trouver_liens(array($objet_lien=>'*'),array(($objet_lien==$objet_source?$objet:$objet_source)=>'*')))) |
||||
return false; |
||||
|
||||
$valeurs = array( |
||||
'id'=>"$table_source-$objet-$id_objet-$objet_lien", // identifiant unique pour les id du form |
||||
'_vue_liee' => $table_source."_lies", |
||||
'_vue_ajout' => $table_source."_associer", |
||||
'_objet_lien' => $objet_lien, |
||||
'id_lien_ajoute'=>_request('id_lien_ajoute'), |
||||
'objet'=>$objet, |
||||
'id_objet'=>$id_objet, |
||||
'objet_source'=>$objet_source, |
||||
'table_source' => $table_source, |
||||
'recherche'=>'', |
||||
'visible'=>0, |
||||
'ajouter_lien'=>'', |
||||
'supprimer_lien'=>'', |
||||
'_oups' => _request('_oups'), |
||||
'editable' => $editable, |
||||
); |
||||
|
||||
return $valeurs; |
||||
} |
||||
|
||||
/** |
||||
* Traiter le post des informations d'édition de liens |
||||
* |
||||
* Les formulaires postent dans trois variables ajouter_lien et supprimer_lien |
||||
* et remplacer_lien |
||||
* |
||||
* Les deux premieres peuvent etre de trois formes differentes : |
||||
* ajouter_lien[]="objet1-id1-objet2-id2" |
||||
* ajouter_lien[objet1-id1-objet2-id2]="nimportequoi" |
||||
* ajouter_lien['clenonnumerique']="objet1-id1-objet2-id2" |
||||
* Dans ce dernier cas, la valeur ne sera prise en compte |
||||
* que si _request('clenonnumerique') est vrai (submit associe a l'input) |
||||
* |
||||
* remplacer_lien doit etre de la forme |
||||
* remplacer_lien[objet1-id1-objet2-id2]="objet3-id3-objet2-id2" |
||||
* ou objet1-id1 est celui qu'on enleve et objet3-id3 celui qu'on ajoute |
||||
* |
||||
* @param string $a |
||||
* @param string|int $b |
||||
* @param int|string $c |
||||
* @param bool $editable |
||||
* @return array |
||||
*/ |
||||
function formulaires_editer_liens_traiter_dist($a,$b,$c,$editable=true){ |
||||
$res = array('editable'=>$editable?true:false); |
||||
list($table_source,$objet,$id_objet,$objet_lien) = determine_source_lien_objet($a,$b,$c); |
||||
if (!$table_source OR !$objet OR !$objet_lien) |
||||
return $res; |
||||
|
||||
|
||||
if (_request('tout_voir')) |
||||
set_request('recherche',''); |
||||
|
||||
|
||||
if (autoriser('modifier',$objet,$id_objet)) { |
||||
// annuler les suppressions du coup d'avant ! |
||||
if (_request('annuler_oups') |
||||
AND $oups = _request('_oups') |
||||
AND $oups = unserialize($oups)){ |
||||
$objet_source = objet_type($table_source); |
||||
include_spip('action/editer_liens'); |
||||
foreach($oups as $oup) { |
||||
if ($objet_lien==$objet_source) |
||||
objet_associer(array($objet_source=>$oup[$objet_source]), array($objet=>$oup[$objet]),$oup); |
||||
else |
||||
objet_associer(array($objet=>$oup[$objet]), array($objet_source=>$oup[$objet_source]),$oup); |
||||
} |
||||
# oups ne persiste que pour la derniere action, si suppression |
||||
set_request('_oups'); |
||||
} |
||||
|
||||
$supprimer = _request('supprimer_lien'); |
||||
$ajouter = _request('ajouter_lien'); |
||||
|
||||
// il est possible de preciser dans une seule variable un remplacement : |
||||
// remplacer_lien[old][new] |
||||
if ($remplacer = _request('remplacer_lien')){ |
||||
foreach($remplacer as $k=>$v){ |
||||
if ($old = lien_verifier_action($k,'')){ |
||||
foreach(is_array($v)?$v:array($v) as $kn=>$vn) |
||||
if ($new = lien_verifier_action($kn,$vn)){ |
||||
$supprimer[$old] = 'x'; |
||||
$ajouter[$new] = '+'; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if ($supprimer){ |
||||
include_spip('action/editer_liens'); |
||||
$oups = array(); |
||||
|
||||
foreach($supprimer as $k=>$v) { |
||||
if ($lien = lien_verifier_action($k,$v)){ |
||||
$lien = explode("-",$lien); |
||||
list($objet_source,$ids,$objet_lie,$idl) = $lien; |
||||
if ($objet_lien==$objet_source){ |
||||
$oups = array_merge($oups, objet_trouver_liens(array($objet_source=>$ids), array($objet_lie=>$idl))); |
||||
objet_dissocier(array($objet_source=>$ids), array($objet_lie=>$idl)); |
||||
} |
||||
else{ |
||||
$oups = array_merge($oups, objet_trouver_liens(array($objet_lie=>$idl), array($objet_source=>$ids))); |
||||
objet_dissocier(array($objet_lie=>$idl), array($objet_source=>$ids)); |
||||
} |
||||
} |
||||
} |
||||
set_request('_oups',$oups?serialize($oups):null); |
||||
} |
||||
|
||||
if ($ajouter){ |
||||
$ajout_ok = false; |
||||
include_spip('action/editer_liens'); |
||||
foreach($ajouter as $k=>$v){ |
||||
if ($lien = lien_verifier_action($k,$v)){ |
||||
$ajout_ok = true; |
||||
list($objet1,$ids,$objet2,$idl) = explode("-",$lien); |
||||
if ($objet_lien==$objet1) |
||||
objet_associer(array($objet1=>$ids), array($objet2=>$idl)); |
||||
else |
||||
objet_associer(array($objet2=>$idl), array($objet1=>$ids)); |
||||
set_request('id_lien_ajoute',$ids); |
||||
} |
||||
} |
||||
# oups ne persiste que pour la derniere action, si suppression |
||||
# une suppression suivie d'un ajout dans le meme hit est un remplacement |
||||
# non annulable ! |
||||
if ($ajout_ok) |
||||
set_request('_oups'); |
||||
} |
||||
} |
||||
|
||||
|
||||
return $res; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Retrouver l'action de liaision demandée |
||||
* |
||||
* Les formulaires envoient une action dans un tableau ajouter_lien |
||||
* ou supprimer_lien |
||||
* |
||||
* L'action est de la forme : objet1-id1-objet2-id2 |
||||
* |
||||
* L'action peut-être indiquée dans la clé ou dans la valeur. |
||||
* Si elle est indiquee dans la valeur et que la clé est non numérique, |
||||
* on ne la prend en compte que si un submit avec la clé a été envoyé |
||||
* |
||||
* @param string $k Clé du tableau |
||||
* @param string $v Valeur du tableau |
||||
* @return string Action demandée si trouvée, sinon '' |
||||
*/ |
||||
function lien_verifier_action($k,$v){ |
||||
if (preg_match(",^\w+-[\w*]+-[\w*]+-[\w*]+,",$k)) |
||||
return $k; |
||||
if (preg_match(",^\w+-[\w*]+-[\w*]+-[\w*]+,",$v)){ |
||||
if (is_numeric($k)) |
||||
return $v; |
||||
if (_request($k)) |
||||
return $v; |
||||
} |
||||
return ''; |
||||
} |
||||
?> |
Loading…
Reference in new issue