diff --git a/application/modules/admin/controllers/ModoController.php b/application/modules/admin/controllers/ModoController.php
index 2c3e09ff850466a75c1ba11a501ef9ca88d1d262..e3eacd352a3f29fe96f4de2f781e0062428c2fbc 100644
--- a/application/modules/admin/controllers/ModoController.php
+++ b/application/modules/admin/controllers/ModoController.php
@@ -76,23 +76,11 @@ class Admin_ModoController extends ZendAfi_Controller_Action {
 
 		$avis = $this->_setAvisAndEntete($avis, $form);
 
-		if ($form->url->getValue()) {
-			// url routing to extract params as if it is a Bokeh url
-			$request = (new Zend_Controller_Router_Rewrite())
-				->route(new Zend_Controller_Request_Http($form->url->getValue()));
-			
-			if ('viewnotice' != $request->getActionName()
-					|| !($notice = Class_Notice::find((int)$request->getParam('id')))
-					|| $notice->getClefAlpha() != $request->getParam('clef')) {
-				$form->url->addError('L\'url saisie ne correspond pas à un permalien de notice');
-				return false;
-			}
-			
-			$avis->setClefOeuvre($notice->getClefOeuvre())->save();
-			$this->_helper->notify($this->view->_('Avis rattaché à la notice "%s"', $notice->getTitrePrincipal()));
+		if ($record = $form->url->getRecord()) {
+			$avis->setClefOeuvre($record->getClefOeuvre())->save();
+			$this->_helper->notify($this->view->_('Avis rattaché à la notice "%s"', $record->getTitrePrincipal()));
 		}
 
-
 		return true;
 	}
 
diff --git a/application/modules/opac/controllers/AbonneController.php b/application/modules/opac/controllers/AbonneController.php
index 56b82d66589bd051d88c5d0be75523e4eefdfd30..98a462bc11f01c2805bfdfe0dc4a745ec31392ca 100644
--- a/application/modules/opac/controllers/AbonneController.php
+++ b/application/modules/opac/controllers/AbonneController.php
@@ -280,20 +280,24 @@ class AbonneController extends ZendAfi_Controller_Action {
 		$form = ZendAfi_Form_Admin_EditAvis::newWith($avis, '');
 		$form->setAttrib('action', $this->view->url());
 		$form->addElement('submit', 'edit-avis-submit', ['label' => 'Valider']);
-		$this->view->form = $form;
 
 		if ($this->_request->isPost()
 				&& $form->isValid($this->_request->getPost())) {
 			$avis
 				->setAvis($form->avis->getValue())
-				->setEntete($form->entete->getValue())
-				->save();
+				->setEntete($form->entete->getValue());
+			if ($record = $form->url->getRecord())
+				$avis->setClefOeuvre($record->getClefOeuvre());
 
-			$this->_javascriptRedirectToReferrer();
-			return;
-		}
+			if ($avis->save()) {
+				$this->_javascriptRedirectToReferrer();
+				return;
+			}
 
+			$form->addModelErrors($avis);
+		}
 
+		$this->view->form = $form;
 		$this->renderPopupResult($this->view->_('Modifier l\'avis "%s"', $avis->getEntete()),
 														 $this->view->render('abonne/editavisnotice.phtml'));
 	}
diff --git a/library/Class/AvisNotice.php b/library/Class/AvisNotice.php
index a1e2a3df6ccad8f44ab2b524b7e7f99717e71ffa..3c01a98e59b768e5815270459e7a8c366603885b 100644
--- a/library/Class/AvisNotice.php
+++ b/library/Class/AvisNotice.php
@@ -311,10 +311,13 @@ class Class_AvisNotice  extends Storm_Model_Abstract {
 
 		$translate = Zend_Registry::get('translate');
 
-		$this->check( $longueur_avis >= $longueur_min && $longueur_avis <= $longueur_max,
-									$translate->_("L'avis doit avoir une longueur comprise entre %s et %s caractères", $longueur_min, $longueur_max));
+		$this->checkAttribute('avis', 
+													$longueur_avis >= $longueur_min && $longueur_avis <= $longueur_max,
+													$translate->_("L'avis doit avoir une longueur comprise entre %s et %s caractères", $longueur_min, $longueur_max));
 
-		$this->check( $this->getEntete(), $translate->_('Vous devez saisir un titre') );
+		$this->checkAttribute('entete',
+													$this->getEntete(), 
+													$translate->_('Vous devez saisir un titre') );
 	}
 
 	public function beforeSave() {
diff --git a/library/ZendAfi/Form/Admin/EditAvis.php b/library/ZendAfi/Form/Admin/EditAvis.php
index 80dfbb91e4d560ed0121961c02a7be4e5100655d..a76ebe79ba31a35a299e325e9ccbb6accd33c696 100644
--- a/library/ZendAfi/Form/Admin/EditAvis.php
+++ b/library/ZendAfi/Form/Admin/EditAvis.php
@@ -39,9 +39,11 @@ class ZendAfi_Form_Admin_EditAvis extends ZendAfi_Form {
 			->setAttrib('action', '')
 			->addElement('text', 'entete', ['label' => $this->_('Entête de l\'avis'),
 																			'size' => '100',
-																			'value' => ''])
+																			'required' => true,
+																			'allowEmpty' => false])
 			->addElement('textarea', 'avis', ['label' => $this->_('Contenu de l\'avis'),
-																				'value' => '']);
+																				'required' => true,
+																				'allowEmpty' => false]);
 	}
 
 
@@ -56,9 +58,9 @@ class ZendAfi_Form_Admin_EditAvis extends ZendAfi_Form {
 
 	public function addPermalinkFor($avis) {
 		if($avis->isAvisNotice()) {
-			$this->addElement('text', 'url', ['label' => 'Permalien de la notice concernée *',
-																				'size' => '100',
-																				'validators' => ['url']]);
+			$this->addElement('localRecordUrl', 'url', 
+												['label' => 'Permalien de la notice concernée',
+												 'size' => '100']);
 		}
 		return $this;
 	}
diff --git a/library/ZendAfi/Form/Element/LocalRecordUrl.php b/library/ZendAfi/Form/Element/LocalRecordUrl.php
new file mode 100644
index 0000000000000000000000000000000000000000..934482afc59650cda320fdcf17a41cbe6f5ef406
--- /dev/null
+++ b/library/ZendAfi/Form/Element/LocalRecordUrl.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * AFI-OPAC 2.0 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+
+
+class ZendAfi_Form_Element_LocalRecordUrl extends Zend_Form_Element_Text {
+	public function init() {
+		$this->addValidator(new ZendAfi_Validate_Url(), true);
+		$this->addValidator(new ZendAfi_Validate_LocalRecordUrl());
+	}
+
+
+	public function getRecord() {
+		return $this->getValidator('ZendAfi_Validate_LocalRecordUrl')->getRecord();
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/Validate/LocalRecordUrl.php b/library/ZendAfi/Validate/LocalRecordUrl.php
new file mode 100644
index 0000000000000000000000000000000000000000..500d6451f2a5a97ef221bcee54ebcbf71bf97fe7
--- /dev/null
+++ b/library/ZendAfi/Validate/LocalRecordUrl.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * AFI-OPAC 2.0 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+
+
+class ZendAfi_Validate_LocalRecordUrl extends Zend_Validate_Abstract {
+	const INVALID_URL = 'invalidUrl';	
+	protected $_messageTemplates = array(self::INVALID_URL   => "'%value%' ne correspond pas à un permalien de notice");
+	protected $_record;
+
+
+	public function isValid($value) {
+		$this->_setValue((string)$value);
+
+		// url routing to extract params as if it is a Bokeh url
+		$request = (new Zend_Controller_Router_Rewrite())
+			->route(new Zend_Controller_Request_Http($value));
+			
+		if ('viewnotice' != $request->getActionName()
+				|| !($record = Class_Notice::find((int)$request->getParam('id')))
+				|| $record->getClefAlpha() != $request->getParam('clef')) {
+			$this->_error(self::INVALID_URL);
+			return false;
+		}
+
+		$this->_record = $record;
+		return true;
+	}
+
+
+	public function getRecord() {
+		return $this->_record;
+	}
+}
+?>
\ No newline at end of file
diff --git a/tests/application/modules/admin/controllers/ModoControllerTest.php b/tests/application/modules/admin/controllers/ModoControllerTest.php
index 8e9c6e48fa01c4fb92b8377b4ac42fe2400ea96f..1e531bb7183fb5e2cd387e0d383c182bacf9a91e 100644
--- a/tests/application/modules/admin/controllers/ModoControllerTest.php
+++ b/tests/application/modules/admin/controllers/ModoControllerTest.php
@@ -318,31 +318,37 @@ class ModoControllerSuggestionAchatDeleteUnknownTest extends ModoControllerSugge
 }
 
 
-class ModoControllerEditAvisCmsTest extends Admin_AbstractControllerTestCase {
+abstract class ModoControllerEditAvisCmsTestCase extends Admin_AbstractControllerTestCase {
 	public function setUp() {
 		parent::setUp();
 
-		$this->fixture('Class_Avis', ['id' => 1,
-																	'date_avis' => '2014-04-16',
-																	'user' =>  $this->fixture('Class_Users', ['id' => 45,
-																																						'login' => 'biquette',
-																																						'password' => 'mysecret']),
-																	'article' => $this->fixture('Class_Article', ['id' => 2,
-																																						'titre' => 'Coucou la biquette',
-																																						'contenu' => 'plop plop']),
-																	'avis' => "Yes you can !",
-																	'entete' => 'Can you accept my merge request ?',
-																	'note' => '3']);
+		$this->fixture('Class_Avis', 
+									 ['id' => 1,
+										'date_avis' => '2014-04-16',
+										'user' =>  $this->fixture('Class_Users', ['id' => 45,
+																															'login' => 'biquette',
+																															'password' => 'mysecret']),
+										'article' => $this->fixture('Class_Article', ['id' => 2,
+																																	'titre' => 'Coucou la biquette',
+																																	'contenu' => 'plop plop']),
+										'avis' => "Yes you can !",
+										'entete' => 'Can you accept my merge request ?',
+										'note' => '3']);
 	}
+}
+
 
 
+class ModoControllerIndexAvisCmsTest extends ModoControllerEditAvisCmsTestCase {
 	/** @test **/
 	public function avisShouldHaveEditLink() {
 		$this->dispatch('admin/modo/aviscms', true);
 		$this->assertXPath('//a[contains(@href, "/modo/edit-aviscms/id/1")]');
 	}
+}
 
 
+class ModoControllerEditAvisCmsTest extends ModoControllerEditAvisCmsTestCase {
 	/** @test **/
 	public function textAreaShouldContainsThisIsATest() {
 		$this->dispatch('admin/modo/edit-aviscms/id/1', true);
@@ -355,20 +361,28 @@ class ModoControllerEditAvisCmsTest extends Admin_AbstractControllerTestCase {
 		$this->dispatch('admin/modo/edit-aviscms/id/1', true);
 		$this->assertXPath('//input[@type="text"][@id="entete"][@value="Can you accept my merge request ?"]');
 	}
+}
+
+
+
+class ModoControllerEditAvisCmsPostTest extends ModoControllerEditAvisCmsTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->postDispatch('admin/modo/edit-aviscms/id/1', 
+												['avis' => 'Ceci est un avis de test modifié!',
+												 'entete' => 'w00t !']);
+		
+	}
 
 
 	/** @test **/
 	public function avisShouldContainsThisIsATestModified() {
-		$this->postDispatch('admin/modo/edit-aviscms/id/1', 
-												['avis' => 'Ceci est un avis de test modifié!']);
 		$this->assertEquals('Ceci est un avis de test modifié!', Class_Avis::find(1)->getAvis());
 	}
 
 
 	/** @test **/
 	public function avisEnTeteShouldContainsWooT() {
-		$this->postDispatch('admin/modo/edit-aviscms/id/1', 
-												['entete' => 'w00t !']);
 		$this->assertEquals('w00t !', Class_Avis::find(1)->getEntete());
 	}
 }
diff --git a/tests/application/modules/opac/controllers/AbonneControllerAvisTest.php b/tests/application/modules/opac/controllers/AbonneControllerAvisTest.php
index 97aa64ce88368712fe9cf065b4cf9651afa02eae..aed9803c75c2e305d564f1c57141ced85e35a2c5 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerAvisTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerAvisTest.php
@@ -779,6 +779,7 @@ class AbonneControllerEditAvisNoticeAdminLoggedActionTest extends AbstractContro
 
 		$this->dispatch('/opac/abonne/editavisnotice/id/54', true);
 		$this->json = json_decode($this->_response->getBody());
+		$this->xpath = new Storm_Test_XPath();
 	}
 
 
@@ -790,7 +791,25 @@ class AbonneControllerEditAvisNoticeAdminLoggedActionTest extends AbstractContro
 
 	/** @test */
 	public function formShouldBePresent() {
-		$this->assertTrue(false !== strpos($this->json->content, '<form '));
+		$this->xpath->assertXPath($this->json->content, '//form[contains(@action, "abonne/editavisnotice")]');
+	}
+
+	
+	/** @test */
+	public function enteteInputShouldBePresent() {
+		$this->xpath->assertXPath($this->json->content, '//input[@name="entete"]');
+	}
+
+
+	/** @test */
+	public function avisTextareaShouldBePresent() {
+		$this->xpath->assertXPath($this->json->content, '//textarea[@name="avis"]');
+	}
+
+
+	/** @test */
+	public function urlInputShouldBePresent() {
+		$this->xpath->assertXPath($this->json->content, '//input[@name="url"]');
 	}
 }
 
@@ -801,11 +820,17 @@ class AbonneControllerEditAvisNoticeAdminLoggedPostActionTest extends AbstractCo
 		parent::setUp();
 		$this->fixture('Class_AvisNotice', ['id' => 54,
 																				'entete' => 'Bonjour !',
-																				'avis' => 'Ceci est le contenu de l\'avis']);
+																				'avis' => 'Ceci est le contenu de l\'avis',
+																				'clef_oeuvre' => 'HUITIEMECOULEURLA-DASTYLE']);
+
+		$this->fixture('Class_Notice', ['id' => 1190178,
+																		'clef_oeuvre' => 'GARCONNIERELA--GREMILLONH-',
+																		'clef_alpha' => 'GARCONNIERELA--GREMILLONH--FLAMMARION-2013-1']);
 
 		$this->postDispatch('/opac/abonne/editavisnotice/id/54', 
 												['entete' => 'bye',
-												 'avis' => 'ceci n\'est pas le contenu'],
+												 'avis' => 'ceci n\'est pas le contenu',
+												 'url' => 'http://localhost/recherche/viewnotice/expressionRecherche/la+garconniere/tri/%2A/facette/T1/clef/GARCONNIERELA--GREMILLONH--FLAMMARION-2013-1/id/1190178'],
 												true);
 
 		$this->avis = Class_AvisNotice::find(54);
@@ -822,6 +847,12 @@ class AbonneControllerEditAvisNoticeAdminLoggedPostActionTest extends AbstractCo
 	public function avisShouldBeCeciNEstPasLeContenu() {
 		$this->assertEquals('ceci n\'est pas le contenu', $this->avis->getAvis());
 	}
+
+
+	/** @test */
+	public function cleOeuvreShouldBeGarconniereLa() {
+		$this->assertEquals('GARCONNIERELA--GREMILLONH-', $this->avis->getClefOeuvre());
+	}
 }
 
 ?>
\ No newline at end of file