7 const LECTURE_PUBLIC
= -1;
8 const LECTURE_NORMAL
= 0;
9 const LECTURE_CATEGORIE
= 1;
11 const ECRITURE_NORMAL
= 0;
12 const ECRITURE_CATEGORIE
= 1;
14 const ITEMS_PER_PAGE
= 25;
16 protected $restriction_categorie = null;
17 protected $restriction_droit = null;
19 static public function transformTitleToURI($str)
21 $str = utils
::transliterateToAscii($str);
23 $str = preg_replace('![^\w\d_-]!i', '-', $str);
24 $str = preg_replace('!-{2,}!', '-', $str);
25 $str = trim($str, '-');
30 // Gestion des données ///////////////////////////////////////////////////////
32 public function _checkFields(&$data)
34 $db = DB
::getInstance();
36 if (isset($data['titre']) && !trim($data['titre']))
38 throw new UserException('Le titre ne peut rester vide.');
41 if (isset($data['uri']) && !trim($data['uri']))
43 throw new UserException('L\'adresse de la page ne peut rester vide.');
46 if (isset($data['droit_lecture']))
48 $data['droit_lecture'] = (int) $data['droit_lecture'];
50 if ($data['droit_lecture'] < -1)
52 $data['droit_lecture'] = 0;
56 if (isset($data['droit_ecriture']))
58 $data['droit_ecriture'] = (int) $data['droit_ecriture'];
60 if ($data['droit_ecriture'] < 0)
62 $data['droit_ecriture'] = 0;
66 if (isset($data['parent']))
68 $data['parent'] = (int) $data['parent'];
70 if ($data['parent'] < 0)
75 if (!$db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE id = ?;', false, $data['parent']))
84 public function create($data = [])
86 $this->_checkFields($data);
87 $db = DB
::getInstance();
89 if (!empty($data['uri']))
91 $data['uri'] = self
::transformTitleToURI($data['uri']);
93 if ($db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE uri = ? LIMIT 1;', false, $data['uri']))
95 throw new UserException('Cette adresse de page est déjà utilisée pour une autre page, il faut en choisir une autre.');
100 $data['uri'] = self
::transformTitleToURI($data['titre']);
102 if (!trim($data['uri']) ||
$db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE uri = ? LIMIT 1;', false, $data['uri']))
104 $data['uri'] .= '_' . date('d-m-Y_H-i-s');
108 $db->simpleInsert('wiki_pages', $data);
109 $id = $db->lastInsertRowId();
111 // On ne peut utiliser un trigger pour insérer dans la recherche
112 // car les tables virtuelles font des opérations qui modifient
113 // last_insert_rowid() et donc résultat incohérent
114 $db->simpleInsert('wiki_recherche', ['id' => $id, 'titre' => $data['titre']]);
119 public function edit($id, $data = [])
121 $db = DB
::getInstance();
122 $this->_checkFields($data);
124 if (isset($data['uri']))
126 $data['uri'] = self
::transformTitleToURI($data['uri']);
128 if ($db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE uri = ? AND id != ? LIMIT 1;', false, $data['uri'], (int)$id))
130 throw new UserException('Cette adresse de page est déjà utilisée pour une autre page, il faut en choisir une autre.');
134 if (isset($data['droit_lecture']) && $data['droit_lecture'] >= self
::LECTURE_CATEGORIE
)
136 $data['droit_ecriture'] = $data['droit_lecture'];
139 if (isset($data['parent']) && (int)$data['parent'] == (int)$id)
144 $data['date_modification'] = gmdate('Y-m-d H:i:s');
146 // Modification de la date de création
147 if (isset($data['date_creation']))
149 // Si la date n'est pas valide tant pis
150 if (!(strtotime($data['date_creation']) > 0))
152 unset($data['date_creation']);
156 $data['date_creation'] = gmdate('Y-m-d H:i:s', $data['date_creation']);
160 $db->simpleUpdate('wiki_pages', $data, 'id = '.(int)$id);
164 public function delete($id)
166 $db = DB
::getInstance();
168 if ($db->simpleQuerySingle('SELECT COUNT(*) FROM wiki_pages WHERE parent = ?;', false, (int)$id))
173 $db->simpleExec('DELETE FROM wiki_revisions WHERE id_page = ?;', (int)$id);
174 //$db->simpleExec('DELETE FROM wiki_suivi WHERE id_page = ?;', (int)$id); FIXME
175 $db->simpleExec('DELETE FROM wiki_recherche WHERE id = ?;', (int)$id);
176 $db->simpleExec('DELETE FROM wiki_pages WHERE id = ?;', (int)$id);
180 public function get($id)
182 $db = DB
::getInstance();
183 return $db->simpleQuerySingle('SELECT *,
184 strftime(\'%s\', date_creation) AS date_creation,
185 strftime(\'%s\', date_modification) AS date_modification
186 FROM wiki_pages WHERE id = ? LIMIT 1;', true, (int)$id);
189 public function getTitle($id)
191 $db = DB
::getInstance();
192 return $db->simpleQuerySingle('SELECT titre FROM wiki_pages WHERE id = ? LIMIT 1;', false, (int)$id);
195 public function getRevision($id, $rev)
197 $db = DB
::getInstance();
198 $champ_id = Config
::getInstance()->get('champ_identite');
200 // FIXME pagination au lieu de bloquer à 1000
201 return $db->simpleQuerySingle('SELECT r.revision, r.modification, r.id_auteur, r.contenu,
202 strftime(\'%s\', r.date) AS date, LENGTH(r.contenu) AS taille, m.'.$champ_id.' AS nom_auteur,
204 FROM wiki_revisions AS r LEFT JOIN membres AS m ON m.id = r.id_auteur
205 WHERE r.id_page = ? AND revision = ? LIMIT 1;', true, (int) $id, (int) $rev);
208 public function listRevisions($id)
210 $db = DB
::getInstance();
211 $champ_id = Config
::getInstance()->get('champ_identite');
213 // FIXME pagination au lieu de bloquer à 1000
214 return $db->simpleStatementFetch('SELECT r.revision, r.modification, r.id_auteur,
215 strftime(\'%s\', r.date) AS date, LENGTH(r.contenu) AS taille, m.'.$champ_id.' AS nom_auteur,
216 LENGTH(r.contenu) - (SELECT LENGTH(contenu) FROM wiki_revisions WHERE id_page = r.id_page AND revision < r.revision ORDER BY revision DESC LIMIT 1)
217 AS diff_taille, r.chiffrement
218 FROM wiki_revisions AS r LEFT JOIN membres AS m ON m.id = r.id_auteur
219 WHERE r.id_page = ? ORDER BY r.revision DESC LIMIT 1000;', SQLITE3_ASSOC
, (int) $id);
222 public function editRevision($id, $revision_edition = 0, $data)
224 $db = DB
::getInstance();
226 $revision = $db->simpleQuerySingle('SELECT revision FROM wiki_pages WHERE id = ?;', false, (int)$id);
228 // ?! L'ID fournit ne correspond à rien ?
229 if ($revision === false)
231 throw new \
RuntimeException('La page demandée n\'existe pas.');
235 if ($revision == 0 && !trim($data['contenu']))
240 // Il faut obligatoirement fournir un ID d'auteur
241 if (empty($data['id_auteur']) && $data['id_auteur'] !== null)
243 throw new \
BadMethodCallException('Aucun ID auteur de fourni.');
246 $contenu = $db->simpleQuerySingle('SELECT contenu FROM wiki_revisions WHERE revision = ? AND id_page = ?;', false, (int)$revision, (int)$id);
248 // Pas de changement au contenu, pas la peine d'enregistrer une nouvelle révision
249 if (trim($contenu) == trim($data['contenu']))
254 // Révision sur laquelle est basée la nouvelle révision
255 // utilisé pour vérifier que le contenu n'a pas été modifié depuis qu'on
256 // a chargé la page d'édition
257 if ($revision > $revision_edition)
259 throw new UserException('La page a été modifiée depuis le début de votre modification.');
262 if (empty($data['chiffrement']))
263 $data['chiffrement'] = 0;
265 if (!isset($data['modification']) ||
!trim($data['modification']))
266 $data['modification'] = null;
268 // Incrémentons le numéro de révision
271 $data['id_page'] = $id;
272 $data['revision'] = $revision;
274 $db->simpleInsert('wiki_revisions', $data);
275 $db->simpleUpdate('wiki_pages', [
276 'revision' => $revision,
277 'date_modification' => gmdate('Y-m-d H:i:s'),
278 ], 'id = '.(int)$id);
283 public function search($query)
285 $db = DB
::getInstance();
286 return $db->simpleStatementFetch('SELECT
287 p.uri, r.*, snippet(wiki_recherche, \'<b>\', \'</b>\', \'...\', -1, -50) AS snippet,
288 rank(matchinfo(wiki_recherche), 0, 1.0, 1.0) AS points
289 FROM wiki_recherche AS r INNER JOIN wiki_pages AS p ON p.id = r.id
290 WHERE '.$this->_getLectureClause('p.').' AND wiki_recherche MATCH \''.$db->escapeString($query).'\'
291 ORDER BY points DESC LIMIT 0,50;');
294 public function setRestrictionCategorie($id, $droit_wiki)
296 $this->restriction_categorie
= $id;
297 $this->restriction_droit
= $droit_wiki;
301 protected function _getLectureClause($prefix = '')
303 if (is_null($this->restriction_categorie
))
305 throw new \
UnexpectedValueException('setRestrictionCategorie doit être appelé auparavant.');
308 if ($this->restriction_droit
== Membres
::DROIT_AUCUN
)
310 throw new UserException('Vous n\'avez pas accès au wiki.');
313 if ($this->restriction_droit
== Membres
::DROIT_ADMIN
)
316 return '('.$prefix.'droit_lecture = '.self
::LECTURE_NORMAL
.' OR '.$prefix.'droit_lecture = '.self
::LECTURE_PUBLIC
.'
317 OR '.$prefix.'droit_lecture = '.(int)$this->restriction_categorie
.')';
320 public function canReadPage($lecture)
322 if (is_null($this->restriction_categorie
))
324 throw new \
UnexpectedValueException('setRestrictionCategorie doit être appelé auparavant.');
327 if ($this->restriction_droit
< Membres
::DROIT_ACCES
)
332 if ($this->restriction_droit
== Membres
::DROIT_ADMIN
333 ||
$lecture == self
::LECTURE_NORMAL ||
$lecture == self
::LECTURE_PUBLIC
334 ||
$lecture == $this->restriction_categorie
)
340 public function canWritePage($ecriture)
342 if (is_null($this->restriction_categorie
))
344 throw new \
UnexpectedValueException('setRestrictionCategorie doit être appelé auparavant.');
347 if ($this->restriction_droit
< Membres
::DROIT_ECRITURE
)
352 if ($this->restriction_droit
== Membres
::DROIT_ADMIN
353 ||
$ecriture == self
::ECRITURE_NORMAL
354 ||
$ecriture == $this->restriction_categorie
)
360 public function getList($parent = 0)
362 $db = DB
::getInstance();
364 return $db->simpleStatementFetch(
365 'SELECT id, revision, uri, titre,
366 strftime(\'%s\', date_creation) AS date_creation,
367 strftime(\'%s\', date_modification) AS date_modification
369 WHERE parent = ? AND '.$this->_getLectureClause().'
370 ORDER BY transliterate_to_ascii(titre) COLLATE NOCASE LIMIT 500;',
376 public function getById($id)
378 $db = DB
::getInstance();
379 $page = $db->simpleQuerySingle('SELECT *,
380 strftime(\'%s\', date_creation) AS date_creation,
381 strftime(\'%s\', date_modification) AS date_modification
383 WHERE id = ?;', true, (int)$id);
390 if ($page['revision'] > 0)
392 $page['contenu'] = $db->simpleQuerySingle('SELECT * FROM wiki_revisions
393 WHERE id_page = ? AND revision = ?;', true, (int)$page['id'], (int)$page['revision']);
397 $page['contenu'] = false;
403 public function getByURI($uri)
405 $db = DB
::getInstance();
406 $page = $db->simpleQuerySingle('SELECT *,
407 strftime(\'%s\', date_creation) AS date_creation,
408 strftime(\'%s\', date_modification) AS date_modification
410 WHERE uri = ?;', true, trim($uri));
417 if ($page['revision'] > 0)
419 $page['contenu'] = $db->simpleQuerySingle('SELECT * FROM wiki_revisions
420 WHERE id_page = ? AND revision = ?;', true, (int)$page['id'], (int)$page['revision']);
424 $page['contenu'] = false;
430 public function listRecentModifications($page = 1)
432 $begin = ($page - 1) * self
::ITEMS_PER_PAGE
;
434 $db = DB
::getInstance();
436 return $db->simpleStatementFetch('SELECT *,
437 strftime(\'%s\', date_creation) AS date_creation,
438 strftime(\'%s\', date_modification) AS date_modification
440 WHERE '.$this->_getLectureClause().'
441 ORDER BY date_modification DESC;', SQLITE3_ASSOC
);
444 public function countRecentModifications()
446 $db = DB
::getInstance();
447 return $db->simpleQuerySingle('SELECT COUNT(*) FROM wiki_pages WHERE '.$this->_getLectureClause().';');
450 public function listBackBreadCrumbs($id)
455 $db = DB
::getInstance();
460 $res = $db->simpleQuerySingle('SELECT parent, titre, uri
461 FROM wiki_pages WHERE id = ? LIMIT 1;', true, (int)$id);
465 'titre' => $res['titre'],
466 'uri' => $res['uri'],
469 $id = (int)$res['parent'];
472 return array_reverse($flat);
475 public function listBackParentTree($id)
477 $db = DB
::getInstance();
483 'children' => $db->simpleStatementFetchAssocKey('SELECT id, parent, titre FROM wiki_pages
484 WHERE parent = ? ORDER BY transliterate_to_ascii(titre) COLLATE NOCASE;',
491 $parent = $db->simpleQuerySingle('SELECT parent FROM wiki_pages WHERE id = ? LIMIT 1;', false, (int)$id);
495 'parent' => $id ?
(int)$parent : null,
496 'titre' => $id ?
(string)$db->simpleQuerySingle('SELECT titre FROM wiki_pages WHERE id = ? LIMIT 1;', false, (int)$id) : 'Racine',
497 'children' => $db->simpleStatementFetchAssocKey('SELECT id, parent, titre FROM wiki_pages
498 WHERE parent = ? ORDER BY transliterate_to_ascii(titre) COLLATE NOCASE;',
499 SQLITE3_ASSOC
, (int)$id)
507 foreach ($flat as $id=>&$node)
509 if (is_null($node['parent']))
515 if (!isset($flat[$node['parent']]['children']))
517 $flat[$node['parent']]['children'] = [];
520 $flat[$node['parent']]['children'][$id] = &$node;