File include/class.wiki.php artifact 700c891077 part of check-in c0e9ecb182


<?php

class Garradin_Wiki
{
    const LECTURE_PUBLIC = -1;
    const LECTURE_NORMAL = 0;
    const LECTURE_CATEGORIE = 1;

    const ECRITURE_NORMAL = 0;
    const ECRITURE_CATEGORIE = 1;

    const ITEMS_PER_PAGE = 25;

    protected $restriction_categorie = null;
    protected $restriction_droit = null;

    static public function transformTitleToURI($str)
    {
        $str = utils::transliterateToAscii($str);

        $str = preg_replace('!\s+!', '-', $str);
        $str = preg_replace('![^a-z0-9_-]!i', '', $str);

        return $str;
    }

    // Gestion des données ///////////////////////////////////////////////////////

    public function _checkFields(&$data)
    {
        if (isset($data['titre']) && !trim($data['titre']))
        {
            throw new UserException('Le titre ne peut rester vide.');
        }

        if (isset($data['uri']) && !trim($data['uri']))
        {
            throw new UserException('L\'adresse de la page ne peut rester vide.');
        }

        if (isset($data['droit_lecture']))
        {
            $data['droit_lecture'] = (int) $data['droit_lecture'];

            if ($data['droit_lecture'] < -1)
            {
                $data['droit_lecture'] = 0;
            }
        }

        if (isset($data['droit_ecriture']))
        {
            $data['droit_ecriture'] = (int) $data['droit_ecriture'];

            if ($data['droit_ecriture'] < 0)
            {
                $data['droit_ecriture'] = 0;
            }
        }

        if (isset($data['parent']))
        {
            $data['parent'] = (int) $data['parent'];

            if ($data['parent'] < 0)
            {
                $data['parent'] = 0;
            }
        }

        return true;
    }

    public function create($data = array())
    {
        $this->_checkFields($data);
        $db = Garradin_DB::getInstance();

        if (!empty($data['uri']))
        {
            $data['uri'] = self::transformTitleToURI($data['uri']);

            if ($db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE uri = ? LIMIT 1;', false, $data['uri']))
            {
                throw new UserException('Cette adresse de page est déjà utilisée pour une autre page, il faut en choisir une autre.');
            }
        }
        else
        {
            $data['uri'] = self::transformTitleToURI($data['titre']);

            if (!trim($data['uri']) || $db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE uri = ? LIMIT 1;', false, $data['uri']))
            {
                $data['uri'] .= '_' . date('d-m-Y_H-i-s');
            }
        }

        $db->simpleInsert('wiki_pages', $data);
        $id = $db->lastInsertRowId();

        // On ne peut utiliser un trigger pour insérer dans la recherche
        // car les tables virtuelles font des opérations qui modifient
        // last_insert_rowid() et donc résultat incohérent
        $db->simpleInsert('wiki_recherche', array('id' => $id, 'titre' => $data['titre']));

        return $id;
    }

    public function edit($id, $data = array())
    {
        $db = Garradin_DB::getInstance();
        $this->_checkFields($data);

        if (isset($data['uri']))
        {
            $data['uri'] = self::transformTitleToURI($data['uri']);

            if ($db->simpleQuerySingle('SELECT 1 FROM wiki_pages WHERE uri = ? AND id != ? LIMIT 1;', false, $data['uri'], (int)$id))
            {
                throw new UserException('Cette adresse de page est déjà utilisée pour une autre page, il faut en choisir une autre.');
            }
        }

        if (isset($data['droit_lecture']) && $data['droit_lecture'] >= self::LECTURE_CATEGORIE)
        {
            $data['droit_ecriture'] = $data['droit_lecture'];
        }

        $data['date_modification'] = new SQLite3_Instruction('CURRENT_TIMESTAMP');

        $db->simpleUpdate('wiki_pages', $data, 'id = '.(int)$id);
        return true;
    }

    public function get($id)
    {
        $db = Garradin_DB::getInstance();
        return $db->simpleQuerySingle('SELECT *,
            strftime(\'%s\', date_creation) AS date_creation,
            strftime(\'%s\', date_modification) AS date_modification
            FROM wiki_pages WHERE id = ? LIMIT 1;', true, (int)$id);
    }

    public function getTitle($id)
    {
        $db = Garradin_DB::getInstance();
        return $db->simpleQuerySingle('SELECT titre FROM wiki_pages WHERE id = ? LIMIT 1;', false, (int)$id);
    }

    public function editRevision($id, $revision_edition = 0, $data)
    {
        $db = Garradin_DB::getInstance();

        $revision = $db->simpleQuerySingle('SELECT revision FROM wiki_pages WHERE id = ?;', false, (int)$id);

        // ?! L'ID fournit ne correspond à rien ?
        if ($revision === false)
        {
            throw new RuntimeException('La page demandée n\'existe pas.');
        }

        // Pas de révision
        if ($revision == 0 && !trim($data['contenu']))
        {
            return true;
        }

        // Il faut obligatoirement fournir un ID d'auteur
        if (empty($data['id_auteur']))
        {
            throw new BadMethodCallException('Aucun ID auteur de fourni.');
        }

        $contenu = $db->simpleQuerySingle('SELECT contenu FROM wiki_revisions WHERE revision = ? AND id_page = ?;', false, (int)$revision, (int)$id);

        // Pas de changement au contenu, pas la peine d'enregistrer une nouvelle révision
        if (trim($contenu) == trim($data['contenu']))
        {
            return true;
        }

        // Révision sur laquelle est basée la nouvelle révision
        // utilisé pour vérifier que le contenu n'a pas été modifié depuis qu'on
        // a chargé la page d'édition
        if ($revision > $revision_edition)
        {
            throw new UserException('La page a été modifiée depuis le début de votre modification.');
        }

        if (empty($data['chiffrement']))
            $data['chiffrement'] = 0;

        if (!isset($data['modification']) || !trim($data['modification']))
            $data['modification'] = null;

        // Incrémentons le numéro de révision
        $revision++;

        $data['id_page'] = $id;
        $data['revision'] = $revision;

        $db->simpleInsert('wiki_revisions', $data);
        $db->simpleUpdate('wiki_pages', array(
            'revision'          =>  $revision,
            'date_modification' =>  new SQLite3_Instruction('CURRENT_TIMESTAMP'),
        ), 'id = '.(int)$id);

        return true;
    }

    public function search($query)
    {
        $db = Garradin_DB::getInstance();
        // FIXME
    }

    public function setRestrictionCategorie($id, $droit_wiki)
    {
        $this->restriction_categorie = $id;
        $this->restriction_droit = $droit_wiki;
        return true;
    }

    protected function _getLectureClause()
    {
        if (is_null($this->restriction_categorie))
        {
            throw new UnexpectedValueException('setRestrictionCategorie doit être appelé auparavant.');
        }

        if ($this->restriction_droit == Garradin_Membres::DROIT_AUCUN)
        {
            throw new UserException('Vous n\'avez pas accès au wiki.');
        }

        if ($this->restriction_droit == Garradin_Membres::DROIT_ADMIN)
            return '1';

        return '(droit_lecture = '.self::LECTURE_NORMAL.' OR droit_lecture = '.self::LECTURE_PUBLIC.'
            OR droit_lecture = '.(int)$this->restriction_categorie.')';
    }

    public function canReadPage($lecture)
    {
        if (is_null($this->restriction_categorie))
        {
            throw new UnexpectedValueException('setRestrictionCategorie doit être appelé auparavant.');
        }

        if ($this->restriction_droit < Garradin_Membres::DROIT_ACCES)
        {
            return false;
        }

        if ($this->restriction_droit == Garradin_Membres::DROIT_ADMIN
            || $lecture == self::LECTURE_NORMAL || $lecture == self::LECTURE_PUBLIC
            || $lecture == $this->restriction_categorie)
            return true;

        return false;
    }

    public function canWritePage($ecriture)
    {
        if (is_null($this->restriction_categorie))
        {
            throw new UnexpectedValueException('setRestrictionCategorie doit être appelé auparavant.');
        }

        if ($this->restriction_droit < Garradin_Membres::DROIT_ECRITURE)
        {
            return false;
        }

        if ($this->restriction_droit == Garradin_Membres::DROIT_ADMIN
            || $ecriture == self::ECRITURE_NORMAL
            || $ecriture == $this->restriction_categorie)
            return true;

        return false;
    }

    public function getList($parent = 0)
    {
        $db = Garradin_DB::getInstance();

        return $db->simpleStatementFetch(
            'SELECT id, revision, uri, titre,
                strftime(\'%s\', date_creation) AS date_creation,
                strftime(\'%s\', date_modification) AS date_modification
                FROM wiki_pages
                WHERE parent = ? AND '.$this->_getLectureClause().'
                ORDER BY titre LIMIT 500;',
            SQLITE3_ASSOC,
            (int) $parent
        );
    }

    public function getById($id)
    {
        $db = Garradin_DB::getInstance();
        $page = $db->simpleQuerySingle('SELECT *,
                strftime(\'%s\', date_creation) AS date_creation,
                strftime(\'%s\', date_modification) AS date_modification
                FROM wiki_pages
                WHERE id = ?;', true, (int)$id);

        if (!$page)
        {
            return false;
        }

        if ($page['revision'] > 0)
        {
            $page['contenu'] = $db->simpleQuerySingle('SELECT * FROM wiki_revisions
                WHERE id_page = ? AND revision = ?;', true, (int)$page['id'], (int)$page['revision']);
        }
        else
        {
            $page['contenu'] = false;
        }

        return $page;
    }

    public function getByURI($uri)
    {
        $db = Garradin_DB::getInstance();
        $page = $db->simpleQuerySingle('SELECT *,
                strftime(\'%s\', date_creation) AS date_creation,
                strftime(\'%s\', date_modification) AS date_modification
                FROM wiki_pages
                WHERE uri = ?;', true, trim($uri));

        if (!$page)
        {
            return false;
        }

        if ($page['revision'] > 0)
        {
            $page['contenu'] = $db->simpleQuerySingle('SELECT * FROM wiki_revisions
                WHERE id_page = ? AND revision = ?;', true, (int)$page['id'], (int)$page['revision']);
        }
        else
        {
            $page['contenu'] = false;
        }

        return $page;
    }

    public function listRecentModifications($page = 1)
    {
        $begin = ($page - 1) * self::ITEMS_PER_PAGE;

        $db = Garradin_DB::getInstance();

        return $db->simpleStatementFetch('SELECT *,
                strftime(\'%s\', date_creation) AS date_creation,
                strftime(\'%s\', date_modification) AS date_modification
                FROM wiki_pages
                WHERE '.$this->_getLectureClause().'
                ORDER BY date_modification DESC;', SQLITE3_ASSOC);
    }

    public function countRecentModifications()
    {
        $db = Garradin_DB::getInstance();
        return $db->simpleQuerySingle('SELECT COUNT(*) FROM wiki_pages WHERE '.$this->_getLectureClause().';');
    }

    public function listBackParentTree($parent)
    {
        $db = Garradin_DB::getInstance();
        $flat = array((int)$parent);

        if ($parent != 0)
        {
            do
            {
                $parent = $db->simpleQuerySingle('SELECT parent FROM wiki_pages WHERE id = ? LIMIT 1;', false, (int)$parent);
                $flat[] = (int)$parent;
            }
            while ($parent != 0);
        }

        foreach ($flat as &$id)
        {
            $id = array(
                'id'        =>  (int)$id,
                'children'  =>  $db->simpleStatementFetch('SELECT id, titre
                    FROM wiki_pages WHERE parent = ? ORDER BY transliterate_to_ascii(titre) COLLATE NOCASE;', SQLITE3_ASSOC, (int)$id),
            );
        }

        $tree = array_reverse($flat);
        $tree = $this->_buildBackParentTree($tree);

        var_dump($tree);
        exit;

        return $tree;
    }

    protected function _buildBackParentTree(&$tree, &$parent = null)
    {
        foreach ($tree as &$elm)
        {
            if (empty($elm['id']))
            {
                $elm['titre'] = 'Racine du site';
            }
            elseif (!empty($parent['children']))
            {
                foreach ($parent['children'] as $c)
                {
                    if ($c['id'] == $elm['id'])
                        $elm['titre'] = $c['titre'];
                }
            }

            if (!empty($elm['children']))
            {
                $this->_buildBackParentTree($elm['children'], $elm);
            }
        }

        return $tree;
    }
}

?>