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éthode | Usage |
|---|---|
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.