Code SQL et PhP
Voici quelques propositions de code.
Base SQL
# Structure de la table `wakka_triples`
#
CREATE TABLE wakka_triples (
ID mediumint(8) unsigned NOT NULL auto_increment,
resource varchar(50) NOT NULL default '',
namespace varchar(100) NOT NULL default '',
property varchar(255) NOT NULL default '',
value text NOT NULL,
UNIQUE KEY ID (ID),
KEY resource (resource),
KEY namespace (namespace),
KEY property (property)
) TYPE=MyISAM;
#
# Contenu de la table `wakka_triples`
#
# TODO
# INSERT INTO wakka_triples VALUES (1, 'wikini', 'wikini', 'IsANamespacePrefixFor', 'http://www.wikini.net/');
# INSERT INTO wakka_triples VALUES (2, 'foaf', 'wikini', 'IsANamespacePrefixFor', 'http://xmlns.com/foaf/0.1/');
Fonctions de gestion des triplets dans wakka.php
<?php
// Triples management
//
// rename GetSingleValue ?
function GetTripleValue($resource, $property) {
$result = $this->LoadSingle
("select value from ".$this->config["table_prefix"]."triples where resource = '$resource' and property = '$property' limit 1");
return $result[value];
}
function GetAllValues($resource, $property) {
$result = $this->LoadAll
("select * from ".$this->config["table_prefix"]."triples where resource = '$resource' and property = '$property'");
return $result;
}
function GetTriplesForResource($resource) {
$result = $this->LoadAll
("select * from ".$this->config["table_prefix"]."triples where resource = '$resource'");
return $result;
}
function GetTriplesForProperty($property) {
$result = $this->LoadAll
("select * from ".$this->config["table_prefix"]."triples where property = '$property'");
return $result;
}
function AddTriple($resource, $namespace, $property, $value) {
// TODO add $user ?
// TODO ? test if the triple already exist ?
$this->Query
("insert into ".$this->config["table_prefix"]."triples values ('', '".$resource."','".$namespace."','".$property."','".$value."')");
// TODO : give an owner to the triple ?
// 2 solutions :
// -- add a column "owner" in the "triple" table (less elegant, faster) ;
// -- or reify the triple (more elegant, slower).
}
function UpdateTripleValue($ID, $new_value) {
$this->Query
("update ".$this->config["table_prefix"]."triples set value='".$new_value."' where ID='".$ID."'");
}
function DeleteTriple($ID) {
$this->Query
("delete from ".$this->config["table_prefix"]."triples where ID='".$ID."'");
}
function GetTripleRights($ID) {
// TODO
}
function ChangeTripleOwner($ID, $new_user) {
//TODO
}
function GetDistinctNamespaces($resource) {
$result = $this->LoadAll
("select distinct namespace from ".$this->config["table_prefix"]."triples where resource = '$resource'");
return $result;
}
function GetNamespace($ns_prefix) {
$result = $this->LoadSingle
("select value from ".$this->config["table_prefix"]."triples where resource = '$ns_prefix' and namespace = 'wikini' and property = 'IsANamespacePrefixFor' limit 1");
if ($result1[value]) return "xmlns:" . $ns_prefix . "=\"" . $result[value] . "\"";
}
function GetConfigValueE($config_name) {
$result = $this->LoadSingle
("select value from ".$this->config["table_prefix"]."triples where resource = 'ThisWiki' and property = '".mysql_escape_string($config_name)."' limit 1");
return $result[value];
}
function GetWakkaNameE() { return $this->GetConfigValueE("name"); }
?>
Action pour gérer les triplets (affichage, modification, création)
<div class="trip">
<?php
// {{triple
// action="show"
// [resource="UneRes"]
// [namespace="UnNS"]
// [property="UnePr"]
// [order="[resource|namespace|property|value]"]
//
// action="modify"
// [resource="UneRes"]
// [namespace="UnNS"]
// [property="UnePr"]
// [order="[resource|namespace|property|value]"]
//
// action="choose"
// resource="UneRes"
// [namespace="UnNS"]
// property="UnePr"
// value="????"
// [order="[resource|namespace|property|value]"]
//
// action="update_silently"
// resource="UneRes"
// [namespace="UnNS"]
// property="UnePr"
// value="????"
//
// action="search_value"
// [resource="UneRes"]
// [namespace="UnNS"]
// [property="UnePr"]
// [order="[resource|namespace|property|value]"]
//
// }}
//
// Defaults ---------------------------
// action = "show"
// resource = $this->GetPageTag;
// namespace = ""
// property = ""
// value=""
// order=""
$action = $this->GetParameter("action");
$resource = $this->GetParameter("resource");
if (!$resource) { $resource=$this->GetPageTag(); }
$property = $this->GetParameter("property");
echo "<p>Action : ", $action, ", resource : ", $resource, ", property : ", $property, "</p>\n";
$ThisLink = $this->Href();
$ThisPage = $this->GetPageTag();
// TODO : add the namespace for GetTriplesForProperty
$NamespacesPrefixList = "<option value=\"\"></option>\n";
$namespaces_triples = $this->GetTriplesForProperty("IsANamespacePrefixFor");
foreach ($namespaces_triples as $triple) {
$NamespacesPrefixList = $NamespacesPrefixList . "<option value=\"" . $triple["resource"] . "\">" . $triple["resource"] . "</option>\n";
}
$NewTripleForm = "<form action=\"" . $ThisLink . "\" method=\"post\">\n" .
"<tr>\n" .
"<td></td>\n" .
"<td>" . $ThisPage . "</td>\n" .
"<td><input name=\"namespace\" size=\"15\" /></td>\n" .
"<td><input name=\"property\" size=\"35\" /></td>\n" .
"<td><input name=\"value\" size=\"35\" /></td>\n" .
"<td><input name=\"submit\" type=\"submit\" value=\"Créer\" /></td>\n" .
"</tr>\n" .
"<input type=\"hidden\" name=\"resource\" value=\"" . $ThisPage. "\" />\n" .
"</form>\n";
// If action = show
if (!$action or $action == "show") {
// without resource and property
if (!$resource AND !$property) {
$array_triples = $this->GetTriplesForResource($this->GetPageTag());
}
// resource="*" property="*"
if ($resource == "*" AND property == "*") {
$array_triples = $this->GetTriplesForResource($this->GetPageTag());
}
// resource="OneValue" property="*"
if ($resource AND $resource !== "*" AND property == "*") {
$array_triples = $this->GetTriplesForResource($this->GetPageTag());
}
// resource="OneValue"
if ($resource AND !$property) {
$array_triples = $this->GetTriplesForResource($resource);
}
// resource="*" property="OneProperty"
if ($resource == "*" AND $property) {
$array_triples = $this->GetTriplesForProperty($property);
}
// property="OneProperty"
if ($resource AND $resource !== "*" AND $property AND $property !== "*") {
$array_triples = $this->GetAllValues($resource, $property);
}
if ($array_triples) {
echo
"<!-- ======= Begin triples =======-->\n",
"<table>\n",
"<tr class=\"tr_title\">\n",
"<td></td>\n",
"<th>Ressource</th>\n",
"<th>Vocabulaire</th>\n",
"<th>Propriété</th>\n",
"<th>Valeur</th>\n",
"</tr>\n";
foreach ($array_triples as $triple) {
$nb++; $stype = gettype($nb/2);
if ($stype == "integer") { $style = "tr_line1"; }
else { $style = "tr_line2"; }
echo
"<tr class=\"", $style, "\">\n",
"<td> <a href=\"", $this->Href(), "&triple=", $triple["ID"], "\">", $triple["ID"], "</a></td>\n",
"<td>", $triple["resource"], "</td>\n",
"<td>", $triple["namespace"], "</td>\n",
"<td>", $triple["property"], "</td>\n",
"<td>", $triple["value"], "</td>\n",
"</tr>\n";
}
}
else {
echo $resource, " ne contient aucune métadonnée\n";
echo $NewTripleForm;
}
echo
"</table>\n",
"<!-- ======= End triples =======-->\n";
}
if ($action == "modify") {
$array_triples = $this->GetTriplesForResource($this->GetPageTag());
if ($array_triples) {
echo
"<!-- ======= Begin triples =======-->\n",
"<table>\n",
"<tr class=\"tr_title\">\n",
"<td></td>\n",
"<th>Ressource</th>\n",
"<th>Vocabulaire</th>\n",
"<th>Propriété</th>\n",
"<th>Valeur</th>\n",
"</tr>\n";
foreach ($array_triples as $triple)
{
$nb++; $stype = gettype($nb/2);
if ($stype == "integer") { $style = "tr_line1"; }
else { $style = "tr_line2"; }
echo
"<form action=\"", $this->Href(), "\" method=\"post\">\n",
"<tr class=\"", $style, "\">\n",
"<td>", $triple["resource"], "</td>\n",
"<td>", $triple["namespace"], "</td>\n",
"<td>", $triple["property"], "</td>\n",
"<td><input name=\"new_value\" size=\"35\" value=\"", $triple["value"], "\" /></td>\n",
"<td><input name=\"submit\" type=\"submit\" value=\"Sauver\" /></td>\n",
"<td><input name=\"submit\" type=\"submit\" value=\"Supprimer\" /></td>\n",
"</tr>\n",
"<input type=\"hidden\" name=\"ID\" value=\"", $triple["ID"], "\" />\n",
"</form>\n";
}
echo $NewTripleForm;
echo
"</table>\n",
"<!-- ======= End triples =======-->\n";
}
else {
echo $this->GetPageTag(), " ne contient aucune métadonnée\n";
echo
"<!-- ======= Begin triples =======-->\n",
"<table>\n",
"<tr>\n",
"<td></td>\n",
"<th>Ressource</th>\n",
"<th>Vocabulaire</th>\n",
"<th>Propriété</th>\n",
"<th>Valeur</th>\n",
"</tr>\n";
echo $NewTripleForm;
echo
"</table>\n",
"<!-- ======= End triples =======-->\n";
}
}
if ($action == "choose") {
if (!$property) { echo "Vous devez spécifier une propriété.\n"; }
else {
$array_triples = $this->GetAllValues($resource, $property);
if ($array_triples) {
echo
"<form method=\"get\" action=\"", $this->Href($resource), "\">\n",
"<select name=\"value\">\n";
foreach ($array_triples as $triple) {
echo
"<option value=\"", $triple["value"], "\">",
$triple["value"],
"</option>\n";
}
echo
"</select>\n",
"<input name=\"submit\" type=\"submit\" value=\"Valider\" />",
"</form>\n";
}
else { echo "<p>Aucune valeur pour la propriété ", $property, "<p>\n";
}
}
}
unset ($this->parameter);
?>
</div>
Modification du handler "show"
Placer le code suivant au début du fichier.
<?php
if ($_POST)
{
// only if saving:
if ($_POST["submit"] == "Sauver")
{
$this->UpdateTripleValue($_POST["ID"], $_POST["new_value"]);
}
if ($_POST["submit"] == "Supprimer")
{
$this->DeleteTriple($_POST["ID"]);
}
if ($_POST["submit"] == "Créer")
{
$this->AddTriple($_POST["resource"], $_POST["namespace"], $_POST["property"], $_POST["value"] );
}
}
?>
<-- et à la fin du fichier -->
<div class="triples_header">
Métadonnées.
</div>
<div class="trip">
<?php
if ($_GET["triple"]) {
$ThisLink = $this->Href()."&triple=".$_GET["triple"];
$ThisPage = $_GET["triple"];
}
else {
$ThisLink = $this->Href();
$ThisPage = $this->GetPageTag();
}
// Simulate that the user asked the triple to be shown
$triple_shown="yes";
// Simulate that the user have the rights
$rights="ok";
// TODO : add the namespace for GetTriplesForProperty
$NamespacesPrefixList = "<option value=\"\"></option>\n";
$namespaces_triples = $this->GetTriplesForProperty("IsANamespacePrefixFor");
foreach ($namespaces_triples as $triple) {
$NamespacesPrefixList = $NamespacesPrefixList . "<option value=\"" . $triple["resource"] . "\">" . $triple["resource"] . "</option>\n";
}
$NewTripleForm =
"<form action=\"" . $ThisLink . "\" method=\"post\">\n" .
"<tr>\n" .
"<td></td>\n" .
"<td>" . $ThisPage . "</td>\n" .
"<td>\n" .
"<select name=\"namespace\">\n" .
$NamespacesPrefixList .
"</select>\n" .
"</td>\n" .
"<td><input name=\"property\" size=\"35\" /></td>\n" .
"<td><input name=\"value\" size=\"35\" /></td>\n" .
"<td><input name=\"submit\" type=\"submit\" value=\"Créer\" /></td>\n" .
"</tr>\n" .
"<input type=\"hidden\" name=\"resource\" value=\"" . $ThisPage . "\" />\n" .
"</form>\n";
if ($triple_shown) {
// echo $this->GetPageTag();
$array_triples = $this->GetTriplesForResource($ThisPage);
if (!$array_triples) { echo $ThisPage, " ne contient aucune métadonnée.\n"; }
echo
"<!-- ======= Begin triples =======-->\n",
"<table>\n",
"<tr class=\"tr_title\">\n",
"<td></td>\n",
"<th>Ressource</th>\n",
"<th>Vocabulaire</th>\n",
"<th>Propriété</th>\n",
"<th>Valeur</th>\n",
"</tr>\n";
// If there is at least a triple
if ($array_triples) {
foreach ($array_triples as $triple) {
// Select a different style from line to line
$nb++; $stype = gettype($nb/2);
if ($stype == "integer") { $style = "tr_line1"; }
else { $style = "tr_line2"; }
//
echo
"<form action=\"", $this->Href(), "\" method=\"post\">\n",
"<tr class=\"", $style, "\">\n",
"<td> <a href=\"", $this->Href(), "&triple=", $triple["ID"], "\">", $triple["ID"], "</a></td>\n",
"<td>", $triple["resource"], "</td>\n";
// TODO : The namespace have to be choosen from a pulldown menu ?
echo
"<td>", $triple["namespace"], "</td>\n";
echo
"<td>", $triple["property"], "</td>\n",
"<td><input name=\"new_value\" size=\"35\" value=\"", $triple["value"], "\" /></td>\n",
"<td><input name=\"submit\" type=\"submit\" value=\"Sauver\" /></td>\n",
"<td><input name=\"submit\" type=\"submit\" value=\"Supprimer\" /></td>\n",
"</tr>\n",
"<input type=\"hidden\" name=\"ID\" value=\"", $triple["ID"], "\" />\n",
"</form>\n";
}
}
// Display the form to enter a new triple, and close the table
echo $NewTripleForm;
echo
"</table>\n",
"<!-- ======= End triples =======-->\n";
}
?>
</div>
Le tout donne l'interface suivante :
Ressource |
Domaine nominal |
Propriété |
Valeur |
Flux RDF en XML
Créer tout d'abord un handler : /page/handler/rdf.php
<?php
if ($this->HasAccess("read"))
{
if (!$this->page)
{
return;
}
else
{
// display RDF page
$array_triples = $this->GetTriplesForResource($this->GetPageTag());
// Find namespaces to be declared
$array_ns = $this->GetDistinctNamespaces($this->GetPageTag());
foreach ($array_ns as $ns) {
if ($this->GetNamespace($ns["namespace"]))
{ $namespaces = $namespaces . $this->GetNamespace($ns["namespace"]) . "\n"; }
}
echo
"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n",
"<rdf:RDF\n",
"xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n",
$namespaces,
">\n\n";
if ($array_triples) {
echo
"<!-- ======= Begin triples =======-->\n";
echo
"<rdf:Description about=\"", $triple["resource"], "\">\n";
foreach ($array_triples as $triple) {
if ($triple["namespace"]) { $namespace = $triple["namespace"].":"; }
else { $namespace = ""; }
echo "<", $namespace, $triple["property"], ">";
echo $triple["value"];
echo "</", $namespace, $triple["property"],">\n";
}
echo
"</rdf:Description>\n\n";
}
else {
echo $this->GetPageTag(), " ne contient aucune métadonnée\n";
}
echo
"\n</rdf:RDF>\n",
"<!-- ======= End triples =======-->\n";
}
}
else
{
return;
}
?>
Puis modifier la fonction "Run" dans wakka.php :
<?php
function Run($tag, $method = "")
{
if(!($this->GetMicroTime()%3)) $this->Maintenance();
$this->ReadInterWikiConfig();
// do our stuff!
if (!$this->method = trim($method)) $this->method = "show";
if (!$this->tag = trim($tag)) $this->Redirect($this->href("", $this->config["root_page"]));
if ((!$this->GetUser() && $_COOKIE["name"]) && ($user = $this->LoadUser($_COOKIE["name"], $_COOKIE["password"]))) $this->SetUser($user, $_COOKIE["remember"]);
$this->SetPage($this->LoadPage($tag, $_REQUEST["time"]));
$this->LogReferrer();
switch ($this->method)
{
case "xml":
header("Content-type: text/xml");
case "raw":
print($this->Method($this->method));
break;
case "rdf":
header("Content-type: text/xml");
print($this->Method($this->method));
break;
default:
print($this->Header().$this->Method($this->method).$this->Footer());
}
}
?>
Reste à faire
- coder la fonction gérant les droits de modification des triplets (j'ai mon idée là-dessus)
- coder le formulaire permettant le choix d'une valeur parmis une liste de valeurs préétablies
- définir le vocabulaire wikini : ce vocabulaire permet au moteur wikini de traiter certaines informations. Par exemple : <foaf> <wikini:IsANamespacePrefixFor?> <http://xmlns.com/foaf/0.1/> permet à Wikini, à travers la fonction GetNamespace?($prefix), de renvoyer le domaine nominal relatif à un préfixe donné.
- lister les paramètres qui doivent être chargés en base à l'installation de cette solution (dont les paramètres de configuration)
- rédiger les cas d'utilisation pour voir si le système est cohérent (voir notamment comment l'administrateur fonctionnel va paramétrer WikiNi à l'aide de ce système)
--
CharlesNepote
Vocabulaire propre à Wikini
Devant la nouveauté et la difficulté (apparente ?) de la tâche je vais procéder de façon empirique, par l'exemple. (On tâchera de lire et relire et peut-être appliquer la notation N3 décrite dans l'incontournable article "
Primer: Getting into RDF & Semantic Web using N3" [en], par Tim Berners-Lee (le papa du web)).