Intégration

Service Redac, contrôleur, rendu public, gotchas

Service Redac

Redac est un service objet sans dépendance au framework. Il s'instancie dans n'importe quel contrôleur en lui passant quatre paramètres.

use Alluvia\Redac\Redac;
use Alluvia\Redac\Rdoc;
use Alluvia\Redac\Rblock;

$redac = new Redac(
    key:          'rdoc_article_42',            // clé de session (unique par ressource)
    initial_doc:  fn() => Rdoc::make_default(), // appelé seulement si session vide
    render_block: fn(Rblock $b) => $this->partial('redac/_block', ['block' => $b])->content,
    inline_tools: $this->inline_tools,
);

// Charger depuis DB (article existant)
if ($article->content) $redac->load_from_json($article->content);
Méthodes
MéthodeUsage
handle_op(array $post)Traite une opération (toggle_mark, add_block…)
handle_sync(array $post)Sync texte sur blur
handle_undo()Pop undo stack, re-render
export_json()Retourne le JSON du document courant
export_html()Retourne le HTML rendu (tous les blocs)

Toutes ces méthodes retournent un array (['type' => 'html'|'json', 'html' => '…', 'data' => […], 'headers' => […]]), jamais une Response. Le contrôleur fait la conversion.

Pattern contrôleur

// Helper de conversion array → Response
protected function redac_response(array $result): Response
{
    $r = $result['type'] === 'json'
        ? $this->json($result['data'])
        : $this->html($result['html']);
    foreach ($result['headers'] as $k => $v) {
        $r = $r->with_header($k, $v);
    }
    return $r;
}

// Factory : instancie Redac pour un article donné
private function make_redac(int $id): Redac { … }

// Endpoints — River passe les params via $this->param(), jamais en signature
public function redac_op(): Response
{
    $id = (int) $this->param('article_id');
    return $this->redac_response(
        $this->make_redac($id)->handle_op($this->request->all_post())
    );
}
Gotcha River : ne jamais mettre les params de route en signature de méthode. River appelle $ctrl->$method() sans arguments. Utiliser $this->param('article_id') à l'intérieur de la méthode.

Routes à déclarer

// Dans roads.php
$r->post('/admin/articles/{article_id}/redac_op',   [Articles_ctrl::class, 'redac_op']);
$r->post('/admin/articles/{article_id}/redac_sync',  [Articles_ctrl::class, 'redac_sync']);
$r->get( '/admin/articles/{article_id}/redac_undo',  [Articles_ctrl::class, 'redac_undo']);
$r->get( '/admin/articles/{article_id}/redac_state', [Articles_ctrl::class, 'redac_state']);

Vue — injecter la config JS

La vue doit injecter window.RPHP_CONFIG avant le bundle JS. C'est par ce pont que PHP communique la liste des outils inline au client.

<script>
window.RPHP_CONFIG = <?= json_encode([
    'inline_tools' => $inline_tools,
    'base_url'     => get_base_url(),
]) ?>
</script>
<!-- puis le bundle -->
<?= $vite->render('redac') ?>

Rendu public (côté lecture)

use Alluvia\Redac\Rdoc;

// Lire depuis DB et rendre en HTML
$doc  = Rdoc::from_json($article->content);
$html = $doc->to_html();  // HTML complet, tous les blocs

to_html() appelle Rblock::to_html() sur chaque bloc. Le rendu est sémantique : <p>, <h2>, <ul><li>, <figure>, <hr>. Les marks sont encodés proprement (htmlspecialchars partout).

Gotchas intégration dashboard

Singletons détruits par hx-swap body : Le dashboard fait hx-swap="innerHTML" sur body lors de l'ouverture de l'éditeur. Cela détruit les singletons JS (inline_menu, tune, panels…) qui avaient été appendés à body au chargement du bundle. Chaque singleton se re-ajoute automatiquement via un guard if (!document.body.contains(el)).
<button> dans un formulaire : Si Rédac est intégré dans un formulaire DT, s'assurer que tous les boutons Rédac ont type="button" — sinon un clic déclenche le submit du formulaire.
Thème clair : Le CSS Rédac définit ses couleurs via des variables --bg-overlay/surface/base. Ces variables doivent être redéfinies pour [class*="-light"] si le dashboard utilise un thème clair, sinon les popups restent sombres.