Intégrer CKeditor dans CakePHP

Descendant de FCKeditor, CKeditor est un puissant éditeur WYSIWYG. Nous allons créer un Assistant ou Helper pour transformer facilement un simple champ de type textarea en éditeur de texte complet, ainsi que le gestionnaire d’images et de fichier multimédia associé, CKfinder. Nous allons aussi voir comment il est possible de restreindre l’accès aux fonctionnalités de CKfinder aux utilisateurs authentifiés uniquement.

1. Installation

Commençons par télécharger CKeditor. Nous récupérons une archive que nous décompressons dans le dossier js de notre application. Nous faisons de même pour CKfinder (version PHP), pour obtenir au final l’arborescence suivante :

_ app
  |_ webroot
      |_ js
          |_ ckeditor
          |_ ckfinder

2. Configuration de CKeditor

Nous créons ensuite un fichier de configuration spécifique à l’application, que nous nommons naturellement app.config.js à l’intérieur du répertoire ckeditor. Ceci n’est qu’un exemple, à charge du lecteur de se documenter sur toutes les options disponibles :

CKEDITOR.editorConfig = function(config)
{
	config.language = 'fr';
	config.entities_latin = false;
	config.width = 640;
	config.height = 320;
	config.toolbar_App =
	[
	    ['Source','-','Save','Preview','-','About'],
	    ['Cut','Copy','Paste','-','Print'],
	    ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
	    '/',
	    ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
	    ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],
	    ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
	    ['Link','Unlink','Anchor'],
	    ['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak'],
	    '/',
	    ['Styles','Format','Font','FontSize'],
	    ['TextColor','BGColor'],
	    ['Maximize', 'ShowBlocks']
	];
	config.toolbar = 'App';
};

3. L’Assistant CkHelper

Voyons maintenant le code de l’Assistant lui-même, que nous recopions dans un nouveau fichier {app}/views/helpers/ck.php :

<?php
class CkHelper extends AppHelper
{
	var $helpers = array('Html', 'Javascript');
 
	function replace($fieldName, $options = array())
	{
		$defaults = array(
 			'customConfig' => '/js/ckeditor/app.config.js',
 			'loadFinder' => true
 		);
 
		$options = array_merge($defaults, $options);
 
	 	$fieldId = $this->domId($fieldName);
 
	 	$loadFinder = $options['loadFinder'];
 
	 	unset($options['loadFinder']);
 
		$script = "\tvar ck_$fieldId = CKEDITOR.replace('$fieldId', {$this->Javascript->object($options)});";
 
		if($loadFinder)
		{
			$script .= "\n\tCKFinder.SetupCKEditor(ck_$fieldId, '/js/ckfinder/');";
		}
 
		return $this->Html->scriptBlock($script);
	}
}
?>

Le code n’est pas très compliqué, l’unique méthode replace() accepte deux arguments :

  • le nom d’un champ de formulaire que nous souhaitons remplacer par CKeditor, typiquement un textarea ;
  • un tableau de paramètres dont deux sont remplis par défaut : le chemin vers notre fichier de configuration globale créé plus haut, et un booléen pour charger le gestionnaire d’images CKfinder. Ce tableau d’options peut permettre de prendre la main sur les variables de configuration du fichier app.config.js si besoin.

4. Utilisation de l’Assistant

Comme n’importe quel Helper, nous devons appeler le nôtre dans un Contrôleur (ou dans l’AppController si tous les contrôleurs doivent l’utiliser) :

class ArticlesController extends AppController
{
	var $helpers = array('Ck');
}

Voyons maintenant une vue de ce contrôleur, dans laquelle nous allons appeler les fichiers javascript nécessaires au bon fonctionnement de CKeditor et CKfinder, et créer un textarea pour le remplacer par l’éditeur :

<?php
// {app}/views/articles/admin_add.ctp
$this->set('title_for_layout', "Ajouter un article");
 
// Appel des fichiers javascript nécessaires
echo $this->Html->script('ckeditor/ckeditor', array('inline' => false));
echo $this->Html->script('ckfinder/ckfinder', array('inline' => false));
?>
 
<?php echo $this->Form->create('Article'); ?> 
 
<fieldset>
	<legend>Nouvel article</legend>
	<?php echo $this->Form->input('title', array('label' => "Titre :")); ?> 
</fieldset>
 
<fieldset>
	<legend>Contenu</legend>
	<?php echo $this->Form->textarea('description'); ?> 
	<?php echo $this->Ck->replace('description'); ?> 
</fieldset>
 
<?php echo $this->Form->end("Valider"); ?>

L’appel des deux fichiers javascript requis ne sera effectif que si nous ajoutons echo $scripts_for_layout quelque part dans le header HTML de notre layout.

Voilà, nous obtenons un puissant éditeur HTML pour enrichir facilement le texte de l’article.

5. Configuration de CKfinder

Nous devons maintenant configurer CKfinder pour qu’il sache où stocker les images et les fichiers multimédias, par exemple le dossier {app}/webroot/files. Nous ouvrons le fichier {app}/webroot/js/ckfinder/config.php et modifions la ligne suivante :

$baseUrl = '/ckfinder/userfiles/';

En :

$baseUrl = '/files/';

Nous prenons garde que le dossier files existe bien et que les droits d’accès sont suffisants (chmod 755).

6. Restriction du CKfinder aux utilisateurs logués

Nous souhaitons que l’accès au gestionnaire multimédia soit tout à fait interdit aux utilisateurs non authentifiés. CKfinder demande d’ailleurs que l’on implémente la méthode CheckAuthentication() qui retourne false par défaut, interdisant tout accès à quiconque, authentifié ou pas. Nous allons donc implémenter cette méthode en retournant false sauf si le composant Auth a bien renseigné la session, prouvant par là que l’utilisateur est logué. Attention, CakePHP utilise un nom de session différent du nom par défaut de PHP, il faut penser à le définir en tout premier lieu, avant d’appeler session_start().

Nous modifions donc le tout début du fichier config.php comme suit :

session_name('CAKEPHP');
session_start();
 
/**
 * This function must check the user session to be sure that he/she is
 * authorized to upload and access files in the File Browser.
 *
 * @return boolean
 */
function CheckAuthentication()
{
	return !empty($_SESSION['Auth']['User']);
}

Cette fois nous pouvons accèder au gestionnaire d’images en cliquant sur l’icône correspondante dans CKeditor.

Pierre-Emmanuel Fringant

Articles connexes

Commentaires

Bonjour, J’ai également commencé récemment la création d’un Helper CKEditor pour CakePHP1.3. La principale différence est qu’il permet d’utiliser la gestion des buffers pour que le code Javascript puisse être placé en fin de page. Si celà peut t’intéresser, j’ai mis le code ici : http://gist.github.com/253193 (mais bon, il est loin d’être fini !)

Pierre

J’ai suivi le tuto,

j’ai l’erreur suivante : Undefined property: View::$Ck [APP/views/administrators/nouvelles_ajouter.ctp, line 11]

qui correspond à :

Html-&gt;script('ckeditor/ckeditor', array('inline' =&gt; false));
?&gt;

[...] Intégrer CKeditor dans CakePHP [...]

excellent comme tous les articles de ce site. L’editeur marche bien mais par contre il m’est impossible de modifier les paramètres du fichier app.config.js. Si je mets par exemple config.width = 500; ça n’a aucun effet. De même si je modifie la liste des options. une idée ?

@William : as-tu donné une taille en colonnes à ton textarea ? Si oui, essaie de l’enlever.

j’ai supprimé la taille en colonnes mais ça ne change rien. D’ailleurs, le changements d’options ne marche pas non plus. On dirai qu’aucun élément du fichier de config ne marche. Et pourtant l’éditeur fonctionne nickel.

@William : J’ai rencontré exactement le même problème que toi. Je l’ai résolu, pour l’instant, en spécifiant dans les URLs du helper « ck.php » le nom du répertoire racine de mon application. j’ai changé :

$defaults = array(
            'customConfig' =&gt; '/js/ckeditor/app.config.js',[...]
par
$defaults = array(
            'customConfig' =&gt; '/Nom<em>de</em>ma_racine/js/ckeditor/app.config.js',[...]

Et idem pour l’URL dans le bloc

if($loadFinder)

Toutefois je ne trouve pas la méthode « propre » (je débute sous cakePHP) donc si quelqu’un a mieux à proposer, je suis preneur. ;)

En espérant que cela t’aidera à résoudre ton problème, cordialement.

Bonjour,

J’ai le même problème que William et RP..

Christophe

bonjour, aprés avoir configurer l’éditeur avec cakephp, je souhaite récupérer des champs de tables d’une base de donnée, et l’insérer dynamiquement dans le texte, c’est possible non ? SOS

@William : J’ai trouvé !

En fait le lien de configuration ne s’affichait pas du tout dans le block javascript, parcequ’il n’est pas spécifier qu’il doit être écrit !

$script = "\tvar ck_$fieldId = CKEDITOR.replace('$fieldId',";
 
            $script .= "{";
 
                $script .= 'customConfig : "'.$options['customConfig'].'"';
 
            $script .= "}";
 
        $script .= ");";

@william: j’ai le méme pb ke vous et voila la solution, remplacer : Ck->replace(‘description’); ?>

par : replace(‘description’); ?>

mais moi j’un autre probleme : Method HtmlHelper::scriptBlock does not exist [CORE\cake\libs\view\helper.php, line 143]

s’il vous plais j’ai besoin de votre aide le plus rapide possible(le temps me press :D )

Merci pour ce tuto !

Bonjour !

Je ne sais pas si les librairies ont changé récemment, mais une petite erreur dans le helper rendait l’utilisation de CkFinder impossible.

Il m’a fallu remplacer, à la ligne :

$script .= « \n\tCKFinder.SetupCKEditor(ck_$fieldId, ‘/js/ckfinder/’); »;

SetupCKEditor par setupCKEditor

Merci pour les infos, en tout cas

J’utilise CakePHP 1.2.7. L’éditeur ne replace pas les textarea. Lorsque je décommente les lignes suivantes: //echo $html->script(‘ckeditor/ckeditor’, array(‘inline’ => false)); //echo $html->script(‘ckfinder/ckfinder’, array(‘inline’ => false));

J’obtient le message d’erreur suivant : Method HtmlHelper::script does not exist [CORE\cake\libs\view\helper.php, line 142]

Lorsque j’utilise la fonction replace, comme dans l’exemple suivant : echo $form->textarea(‘shortdesc’); echo $ck->replace(‘shortdesc’, array(‘label’ => « Description courte : »));

J’obtient le message suivant : echo $form->textarea(‘shortdesc’); echo $ck->replace(‘shortdesc’, array(‘label’ => « Description courte : »));

Quelqu’un peut m’aider à corriger mon problème s.v.p.?

Merci

Salut.

@Jérémie : je confirme. Si on ne mets pas le « s » de « Setup » en minuscule, le bouton « Explorer le serveur » n’apparaît pas.

J’ai un autre problème par contre, lorsque je clique sur ce bouton, j’obtiens cette erreur :

getDocumentRootPath() . $baseUrl; } $utilsSecurity =& CKFinderConnectorCoreFactory::getInstance(« UtilsSecurity »); $uti… …

La popup s’affiche bien, mais ce long message d’erreur (pas en intégralité ici) apparaît et empêche d’utiliser Ckfinder… :S

Quelqu’un a-t-il eu ce problème et a réussi à le résoudre ?

Merci d’avance.

@MakeItSmile : Pourtant, normalement, le Javascript-object() dans

$script = "&#092;tvar ck_$fieldId = CKEDITOR.replace('$fieldId', {$this-&gt;Javascript-&gt;object($options)});";
se charge de ça, et chez moi ça fonctionne !

Par contre, le helper Javascript est déprécié à l’avenir, donc il vaut mieux utiliser le helper Js à la place qui fait la même chose.

Et je +1 pour le setupCKEditor au lieu de SetupCKEditor ; du coup, le code complet et fonctionnel (pour moi, CakePHP v 1.3.4) ça donne :

 '/js/ckeditor/app.config.js',
            'loadFinder' =&gt; true
        );
 
        $options = array_merge($defaults, $options);
 
        $fieldId = $this-&gt;domId($fieldName);
 
        $loadFinder = $options['loadFinder'];
 
        unset($options['loadFinder']);
 
        $script = "\tvar ck_$fieldId = CKEDITOR.replace('$fieldId', {$this-&gt;Js-&gt;object($options)});";
 
        if($loadFinder)
        {
            $script .= "\n\tCKFinder.setupCKEditor(ck_$fieldId, '/js/ckfinder/');";
        }
 
        return $this-&gt;Html-&gt;scriptBlock($script, array('inline' =&gt; false));
    }
}
?&gt;

J’ai aussi rajouté l’option

array('inline' =&gt; false)
pour que le script se mette bien dans le $scriptsforlayout; que j’ai personnellement mis en bas de page. Sinon le code Js se mettait directement dans le formulaire en milieu de page html, et ne fonctionnait d’ailleurs pas car CKEditor était appelé en bas de page…

mmmh, mon commentaire a un peu souffert de la « sanitazation » ! Retrouvez le code complet ici : http://gist.github.com/618139

Bonjour, j’ai intégré ce Helper et tout fonctionne très bien. Cependant, dès que mon RTE contient un peu trop de texte, au bout de quelques actions, il devient très lent…

Par exemple je surligne du texte, je clique sur « mettre en gras » (B) et il me faut bien 5 secondes pour que je puisse faire une autre action, tout mon onglet est freezé pendant ce temps là…

Je voulais savoir si quelqu’un avait déjà ressenti ce genre de ralentissement et s’il savait d’où ça vient ?

Merci beaucoup

Pour ceux qui ont le fichier de configuration ‘app.config.js’ qui n’est pas pris en compte, il suffit d’aller dans ck.php et de modifier

'customConfig' =&gt; '/js/ckeditor/app.config.js',
Pour
'customConfig' =&gt;'app.config.js',

Chez moi cela fonctionne.

Bonjour,

Tout d’abord excellent tuto !

Pour moi un résultat un peu exotique: lors du premier chargement, ok, mais lors de la soumission du formulaire, erreur JavaScript: Uncaught [CKEDITOR.editor] The instance « PageContenu » already exists :: prototype.js

le champs en question ayant le nom « data['Page']['contenu'].

Merci à la bonne âme qui pourra m’aider.

Bien j’ai résolu mon problème, il venait du fait que mon site utilise AJAX.

Donc, en d’autre terme, l’éditeur une fois créé reste dans le DOM (même en changeant de page) et dès qu’on a le malheur de recharger la même page: collision d’ID dans le conteneur d’instance (CKEDITOR.instances). De plus, le contenu du textarea n’est pas mis à jour.

Il faut donc forcer manuellement la résolution de ces problèmes:

  • Premièrement dans le Helper, ajouter la ligne suivant au dessus du CKEDITOR.replace()
//Supprime précédent éditeur ayant le même ID
        $script = "\tif(CKEDITOR.instances['$fieldId']!=undefined){CKEDITOR.instances['$fieldId'].destroy();}";
        $script .= "\n\tvar ck_$fieldId = CKEDITOR.replace('$fieldId', {$this-&gt;Javascript-&gt;object($options)});";
  • Puis sur le bouton de soumission AJAX, un petit callback pour mettre à jour le champs de texte
echo $this-&gt;Ajax-&gt;submit("Modifier", array('url' =&gt; array('controller' =&gt; 'pages', 'action' =&gt; 'edit'), 'update' =&gt; 'content_admin', 'before' =&gt; 'for(k in CKEDITOR.instances){CKEDITOR.instances[k].updateElement()};'));

Et voilà, ça fonctionne avec un site en AJAX !

Bonjour à tous,

Merci beaucoup pour tout les excellents tutos présents sur ce site…d’une précision exceptionnelle alors un grand bravo !!

Juste une petite remarque pour ceux qui souhaitent intégrer cakephp dans un sous-répertoire (dans EasyPhp/www/mon_site/ par exemple), il faut modifier la ligne du helper :

$script .= "CKFinder.SetupCKEditor(ck_$fieldId, '/js/ckfinder/');";
par
$script .= "CKFinder.setupCKEditor(ck_$fieldId, '".$this->webroot."js/ckfinder/');";
Ainsi, le CKFinder trouvera la bonne page à charger sans se soucier du répertoire

Participez

Pour insérer une portion de code, utilisez <pre lang="php">...</pre>