diff --git a/library/Class/Article.php b/library/Class/Article.php
index 2842a16559a7235134aa3193bd0425dbebd7ecdf..bc029c2d136f9d38e3b8605290cbbec95c4a62aa 100644
--- a/library/Class/Article.php
+++ b/library/Class/Article.php
@@ -637,7 +637,7 @@ class Class_Article extends Storm_Model_Abstract {
 
 	public function getRefusMessage() {
 		if (!parent::_get('refus_message'))
-			return  Class_AdminVar::getWorkflowTextMailArticleRefused();
+			return Class_AdminVar::getWorkflowTextMailArticleRefused();
 		return parent::_get('refus_message');
 	}
 
@@ -734,12 +734,12 @@ class Class_Article extends Storm_Model_Abstract {
 	 */
 	public function _get($field) {
 		if ($this->shouldOverrideAttribute($field))
-			return $this->_getCustomField($field);
+			return parent::_get($field);
 
 		if ($this->isTraduction())
 			return $this->getArticleOriginal()->_get($field);
 
-		return $this->_getCustomField($field);
+		return parent::_get($field);
 	}
 
 	/**
@@ -749,19 +749,18 @@ class Class_Article extends Storm_Model_Abstract {
 	 */
 	public function _set($field, $value) {
 		if ($this->shouldOverrideAttribute($field))
-			return $this->_setCustomField($field,$value);
+			return parent::_set($field,$value);
 
-		if ($this->isTraduction()) {
+		if ($this->isTraduction())
 			return $this->getArticleOriginal()->_set($field, $value);
-		} else {
-			return $this->_setCustomField($field, $value);
-		}
+
+		return parent::_set($field, $value);
+
 	}
 
 
 	protected function _updateDateMaj() {
-		$date = new Class_Date();
-		$this->setDateMaj($date->DateTimeDuJour());
+		$this->setDateMaj(date('Y-m-d H:i:s', $this->getCurrentTime()));
 	}
 
 	public function beforeSave() {
@@ -1238,7 +1237,5 @@ class Class_Article extends Storm_Model_Abstract {
 		$visitor->visitTitre($this->getTitre())
 						->visitTypeDocId($this->getTypeDocId());
 	}
-
 }
-
 ?>
\ No newline at end of file
diff --git a/library/Class/ArticleCategorie.php b/library/Class/ArticleCategorie.php
index 0cf033ba89f4b62033892e7d228120c850880f78..2b0d8dfe264f7c0637cc817686364e9129dd532c 100644
--- a/library/Class/ArticleCategorie.php
+++ b/library/Class/ArticleCategorie.php
@@ -37,7 +37,7 @@ class ArticleCategorieLoader extends Storm_Model_Loader {
 
 
 class Class_ArticleCategorie extends Storm_Model_Abstract {
-	use	Trait_TreeViewableCategorie, Trait_TreeNode,Trait_PermissionTargetable;
+	use	Trait_TreeViewableCategorie, Trait_TreeNode,Trait_PermissionTargetable, Trait_CustomFields;
 
 
 	protected
diff --git a/library/Class/Catalogue.php b/library/Class/Catalogue.php
index 5c09d1939b0ccc951ca7d07703ad1368320345e8..b442552b0a2cf8c8c0fb0b2bc44074fd2d5f103e 100644
--- a/library/Class/Catalogue.php
+++ b/library/Class/Catalogue.php
@@ -570,10 +570,11 @@ class CatalogueLoader extends Storm_Model_Loader {
 
 
 class Class_Catalogue extends Storm_Model_Abstract {
-	use Trait_TreeNode, Trait_Translator;
+	use Trait_TreeNode, Trait_Translator, Trait_CustomFields;
 
 	const CODE_FACETTE = 'Q';
 
+
 	protected
 		$_table_name = 'catalogue',
 		$_table_primary = 'ID_CATALOGUE',
diff --git a/library/Class/CustomField/Model.php b/library/Class/CustomField/Model.php
index bea06b412ada75a8f5ff507b90cafd71dacd619d..eaeb8bb9c9f7d49d92c4f32b95328873dbce2cc5 100644
--- a/library/Class/CustomField/Model.php
+++ b/library/Class/CustomField/Model.php
@@ -27,7 +27,7 @@ class Class_CustomField_Model {
 
 	protected static $_models = [];
 
-	protected $_configuration;
+	protected $_configuration, $_mapping;
 
 	public static function registerAll($array_of_models_configuration) {
 		static::$_models = [];
@@ -98,6 +98,7 @@ class Class_CustomField_Model {
 		return $this->getFields();
 	}
 
+
 	public function getFields() {
 		return Class_CustomField::findAllBy(['model' => $this->getId(),
 																				 'order' => 'priority']);
@@ -105,16 +106,68 @@ class Class_CustomField_Model {
 
 
 	public function find($id) {
-		$loader = call_user_func([self::CLASS_PREFIX.$this->getId(), 'getLoader']);
+		$loader = $this->getCustomizedClassLoader();
 		if (!$instance = $loader->find($id))
 			$instance = $loader->newInstance();
 		return new Class_CustomField_ModelValues($instance, $this);
 	}
 
 
+	public function getCustomizedClassLoader() {
+		return call_user_func([self::CLASS_PREFIX.$this->getId(), 'getLoader']);
+	}
+
+
+	public function getFieldIdByName($name) {
+		$this->initMapping();
+		return isset($this->_mapping[$name])
+			? $this->_mapping[$name] : null;
+	}
+
+
+	public function addField($name, $type, $options='') {
+		$this->initMapping();
+		if (array_key_exists($name, $this->_mapping))
+			return;
+
+		$meta = Class_CustomField_Meta::newInstance(['label' => $name,
+																								 'field_type' => $type,
+																								 'options_list' => $options]);
+		$meta->save();
+
+		$field = Class_CustomField::newInstance(['meta_id' => $meta->getId(),
+																						 'priority' => 1,
+																						 'model' => $this->getId()]);
+		$field->save();
+		$this->_mapping[$name] = $field->getId();
+	}
+
+
+	public function findFirstByCustomFieldValue($name, $value) {
+		if (!$id = $this->getFieldIdByName($name))
+			return null;
+
+		if (!$value = Class_CustomField_Value::findFirstBy(['custom_field_id' => $id,
+																											 'value' => $value]))
+			return null;
+
+		return $this->getCustomizedClassLoader()->find($value->getModelId());
+	}
+
+
 	public function getSousCategories() {
 		return [];
 	}
+
+
+	protected function initMapping() {
+		if (isset($this->_mapping))
+			return ;
+		$this->_mapping=[];
+		foreach ($this->getFields() as $field) {
+			$this->_mapping[$field->getLabel()]=$field->getId();
+		}
+	}
 }
 
 
diff --git a/library/Class/CustomField/ModelConfiguration/ArticleCategorie.php b/library/Class/CustomField/ModelConfiguration/ArticleCategorie.php
new file mode 100644
index 0000000000000000000000000000000000000000..d1d62ddcbafd0abda5ebc7502742a800d696d67d
--- /dev/null
+++ b/library/Class/CustomField/ModelConfiguration/ArticleCategorie.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH 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).
+ *
+ * BOKEH 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 BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_CustomField_ModelConfiguration_ArticleCategorie extends Class_CustomField_ModelConfiguration {
+    public function __construct() {
+        $this->_class_name = 'ArticleCategorie';
+        $this->_label = $this->_('ArticleCategorie');
+        $this->_edit_url = [
+            'module' => 'admin',
+            'controller' => 'cms',
+            'action' => 'edit'];
+    }
+}
+?>
\ No newline at end of file
diff --git a/library/Class/CustomField/ModelConfiguration/Catalogue.php b/library/Class/CustomField/ModelConfiguration/Catalogue.php
new file mode 100644
index 0000000000000000000000000000000000000000..cf2d2a6f796bc019aead32c52744296c1f1e44f2
--- /dev/null
+++ b/library/Class/CustomField/ModelConfiguration/Catalogue.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH 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).
+ *
+ * BOKEH 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 BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_CustomField_ModelConfiguration_Catalogue extends Class_CustomField_ModelConfiguration {
+    public function __construct() {
+        $this->_class_name = 'Catalogue';
+        $this->_label = $this->_('Catalogue');
+        $this->_edit_url = [
+            'module' => 'admin',
+            'controller' => 'cms',
+            'action' => 'edit'];
+    }
+}
+?>
\ No newline at end of file
diff --git a/library/Class/CustomField/ModelConfiguration/Sitotheque.php b/library/Class/CustomField/ModelConfiguration/Sitotheque.php
new file mode 100644
index 0000000000000000000000000000000000000000..3462bb1560fcca971c3cbde6d7203b7509848988
--- /dev/null
+++ b/library/Class/CustomField/ModelConfiguration/Sitotheque.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH 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).
+ *
+ * BOKEH 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 BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_CustomField_ModelConfiguration_Sitotheque extends Class_CustomField_ModelConfiguration {
+    public function __construct() {
+        $this->_class_name = 'Sitotheque';
+        $this->_label = $this->_('Sitotheque');
+        $this->_edit_url = [
+            'module' => 'admin',
+            'controller' => 'cms',
+            'action' => 'edit'];
+    }
+}
+?>
\ No newline at end of file
diff --git a/library/Class/CustomField/ModelConfiguration/SitothequeCategorie.php b/library/Class/CustomField/ModelConfiguration/SitothequeCategorie.php
new file mode 100644
index 0000000000000000000000000000000000000000..47b092e295703022f4c9892d290d9829ea203bfa
--- /dev/null
+++ b/library/Class/CustomField/ModelConfiguration/SitothequeCategorie.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH 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).
+ *
+ * BOKEH 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 BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_CustomField_ModelConfiguration_SitothequeCategorie  extends Class_CustomField_ModelConfiguration {
+    public function __construct() {
+        $this->_class_name = 'SitothequeCategorie';
+        $this->_label = $this->_('Catégorie de sitothèque');
+        $this->_edit_url = [
+            'module' => 'admin',
+            'controller' => 'sito',
+            'action' => 'edit'];
+    }
+}
+?>
\ No newline at end of file
diff --git a/library/Class/CustomField/ModelValues.php b/library/Class/CustomField/ModelValues.php
index a72d9080b1fcc758a9b38ae0324da27d33c5565b..8953e2c074091fe9ea94804f149c3e27105636cd 100644
--- a/library/Class/CustomField/ModelValues.php
+++ b/library/Class/CustomField/ModelValues.php
@@ -56,12 +56,30 @@ class Class_CustomField_ModelValues {
 
 
 	public function setFieldValue($custom_field_id, $value) {
-		$instance = $this->getFieldValues()[$custom_field_id];
+		$instance = $this->getFieldValue($custom_field_id);
 		$instance->setValue($value);
 		return $this;
 	}
 
 
+	public function setFieldValueByName($name, $value) {
+		if ($id = $this->_model->getFieldIdByName($name))
+			$this->setFieldValue($id, $value);
+	}
+
+
+	public function getFieldValue($custom_field_id) {
+		return $this->getFieldValues()[$custom_field_id];
+	}
+
+
+	public function getFieldValueByName($name) {
+		return ($id = $this->_model->getFieldIdByName($name))
+			? $this->getFieldValue($id)
+			: null;
+	}
+
+
 	public function getFieldValues() {
 		if (isset($this->_values))
 			return $this->_values;
diff --git a/library/Class/Import/Typo3.php b/library/Class/Import/Typo3.php
index e7cd665f3603924f5f755396f70ce6b2e7f07c0c..e855a01705ca543f8c839b39e1a6b3ea4e6168c4 100644
--- a/library/Class/Import/Typo3.php
+++ b/library/Class/Import/Typo3.php
@@ -19,21 +19,21 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 class Class_Import_Typo3 {
+	use Trait_TimeSource;
   const DEFAULT_CAT_ID = 30000;
-	const BOKEH_IMG_URL="http://www.mediathequeouestprovence.fr/uploads/";
+	const BOKEH_IMG_URL = "http://www.mediathequeouestprovence.fr/uploads/";
 //	const BOKEH_IMG_URL="http://web.afi-sa.net/miop-test.net/userfiles/image/uploads/";
-	const BOKEH_ATTACHMENT_URL="http://www.mediathequeouestprovence.fr/fileadmin/fichiers/";
+	const BOKEH_ATTACHMENT_URL = "http://www.mediathequeouestprovence.fr/fileadmin/fichiers/";
 //	const BOKEH_ATTACHMENT_URL="http://web.afi-sa.net/miop-test.net/userfiles/file/";
-	const BOKEH_FILEADMIN_URL= "http://www.mediathequeouestprovence.fr/fileadmin/";
+	const BOKEH_FILEADMIN_URL = "http://www.mediathequeouestprovence.fr/fileadmin/";
 //	const BOKEH_FILEADMIN_URL= "http://web.afi-sa.net/miop_test.net/userfiles/image/";
 
-	const  FOREIGN_UID_DATETIME=[867,36];
-	const UID_TYPO3_CF='uid_typo3';
+	const FOREIGN_UID_DATETIME = [867,36];
+	const UID_TYPO3_CF = 'uid_typo3';
 
 	protected
 		$user_mapper,
-		$unknown_koha_urls = [],
-		$meta;
+		$unknown_koha_urls = [];
 
   public function __construct() {
     $this->t3db = new Typo3DB();
@@ -54,59 +54,90 @@ class Class_Import_Typo3 {
     $this->errors = [];
     $this->domaine_map = new DomaineMap();
 		$this->userMap = new UserMap();
-		$this->createCustomField();//		Class_CustomField_model::register(new Class_CustomField_modelConfiguration('
-
-
+		$this->createCustomField();
   }
 
+
 	public function createCustomField() {
-		return Class_Article::addCustomField(self::UID_TYPO3_CF, Class_CustomField_Meta::TEXT_INPUT);
+		$to_customize = ['Class_Article', 'Class_ArticleCategorie',
+										 'Class_Catalogue', 'Class_Sitotheque', 'Class_SitothequeCategorie'];
+
+		foreach($to_customize as $class_name)
+			call_user_func_array([$class_name, 'addCustomField'],
+													 [self::UID_TYPO3_CF, Class_CustomField_Meta::TEXT_INPUT]);
 	}
 
 
 	public function setTypo3DB($t3db) {
-		$this->t3db=$t3db;
+		$this->t3db = $t3db;
 		return $this;
 	}
 
 
-  public function run($what = 'all') {
+  public function run($what='all', $last_update=null) {
 		$_SERVER['HTTP_HOST']='localhost';
+		$logger = Class_Import_Typo3_Logs::getInstance();
+
+		if ('update' == $what && !$last_update) {
+			$logger->addErrorRow("Mode mise à jour demandé sans date de référence");
+			return $logger->report();
+		}
 
 		if ($what == 'update') {
-			Class_Import_Typo3_Logs::getInstance()->addLogRow("\n\n ******** Mise a jour uniquement");
-      $this->updateCategoriesForDossiersDocumentaires();
+			list($day, $month, $year, $hour, $minute) = split('[/ : -]', $last_update);
 
+			$last_update_timestamp = mktime($hour, $minute, 0, $month, $day, $year);
+
+			$logger->addLogRow("\n\n ******** Mise a jour uniquement");
+			$this->updateCategories($last_update_timestamp);
+
+			$logger->addLogRow("\n\n ******** Mise a jour Articles");
+			$this->updateArticles($last_update_timestamp);
+
+			$logger->addLogRow("\n\n ******** Mise a jour Articles Pages");
+			$this->updateArticlePages($last_update_timestamp);
+
+			$logger->addLogRow("\n\n ******** Détection des dossiers documentaires");
+      $this->updateCategoriesForDossiersDocumentaires();
 		}
+
     if ($what == 'all' || $what == 'users') {
-      Class_Import_Typo3_Logs::getInstance()->addLogRow("\n\n ******** Importing users");
+      $logger->addLogRow("\n\n ******** Importing users");
       $this->import_user();
     }
 
+		if ($what == 'docu') {
+			$logger->addLogRow("\n\n ******** Détection des dossiers documentaires");
+      $this->updateCategoriesForDossiersDocumentaires();
+		}
+
     if ($what == 'all' || $what == 'articles') {
-      Class_Import_Typo3_Logs::getInstance()->addLogRow("\n\n ******** Importing categories");
+      $logger->addLogRow("\n\n ******** Importing categories");
       $this->import_categories();
 
-      Class_Import_Typo3_Logs::getInstance()->addLogRow("\n\n ******** Importing articles pages");
+      $logger->addLogRow("\n\n ******** Importing articles pages");
       $this->importArticlesPages();
 
-      Class_Import_Typo3_Logs::getInstance()->addLogRow("\n\n ******** Importing articles");
+      $logger->addLogRow("\n\n ******** Importing articles");
       $this->importArticles();
 
-      Class_Import_Typo3_Logs::getInstance()->addLogRow("\n\n ******** Importing events");
+      $logger->addLogRow("\n\n ******** Importing events");
       $this->importCalendar();
 
-      Class_Import_Typo3_Logs::getInstance()->addLogRow("\n\n ******** Importing sites");
+      $logger->addLogRow("\n\n ******** Importing sites");
       $this->importSites();
+
+			$logger->addLogRow("\n\n ******** Détection des dossiers documentaires");
+      $this->updateCategoriesForDossiersDocumentaires();
     }
 
-		return Class_Import_Typo3_Logs::getInstance()->report();
+		return $logger->report();
   }
 
 
   public function import_user() {
+		$this->userMap->init();
     $t3users = $this->t3db->findAllUsers();
-
     foreach($t3users as $t3user) {
 			$this->userMap->newUser($t3user);
     }
@@ -115,6 +146,33 @@ class Class_Import_Typo3 {
   }
 
 
+	public function updateCategory($category,$t3_category)  {
+		$category->setLibelle($t3_category['title']);
+		$category->save();
+	}
+
+
+	public function updateCategories($update_date) {
+    $this->news_categories_map = new ArticleCategoriesMap('Non classé', $this->domaine_map);
+
+    $t3categories = $this->t3db->findAllNewsCatSince($update_date);
+
+		foreach ($t3categories as $t3category)  {
+			if ($category = ArticleCategoriesMap::getCategory($t3category['uid'])) {
+				$this->updateCategory($category,$t3category);
+				continue;
+			}
+
+			$this->news_categories_map->newCategory($t3category['title'],
+																							$t3category['uid'],
+																							$t3category['parent_category']);
+
+			$this->news_categories_map->fixParentCategory($t3category['uid'],
+																										$t3category['parent_category']);
+		}
+	}
+
+
   public function import_categories() {
 		Class_Article::deleteBy([]);
     Class_ArticleCategorie::deleteBy([]);
@@ -123,8 +181,6 @@ class Class_Import_Typo3 {
     Class_Sitotheque::deleteBy([]);
     Class_SitothequeCategorie::deleteBy([]);
 
-		$meta = Class_Article::getMeta('uid_typo3');
-
     $this->reset_auto_increment();
 
     $this->cal_categories_map= new CalendarCategoriesMap('Agenda', $this->domaine_map);
@@ -145,43 +201,51 @@ class Class_Import_Typo3 {
 
   public function importSites() {
     $t3news = $this->t3db->findAllSites();
-
-    foreach($t3news as $new) {
+    foreach($t3news as $new)
 			$element = $this->traceUnknownKohaUrls(
-																	function() use ($new){
-																		return $this->createSito($new);
-																	},
-																 $new['uid']);
-
-		}
-
+																						 function() use ($new) {
+																							 return $this->createSito($new);
+																						 },
+																						 $new['uid']);
 	}
 
+
 	public function createSito($new) {
-      $date_creation = date("Y-m-d H:i:s", $new['crdate']);
-      $element = Class_Sitotheque::newInstance(['id_cat' => $this->sites_categories_map->find($new['category'])->getId(),
-                                                'date_maj' => $date_creation,
+      $date_maj = date("Y-m-d H:i:s", $new['crdate']);
+			$id_cat = $this->sites_categories_map->find($new['category'])->getId();
+			$url = $this->convertKohaToBokehUrl($this->format_url($new['ext_url']));
+			$tags = str_replace(', ', ';', $new['tx_danpextendnews_tags']);
+
+      $element = Class_Sitotheque::newInstance(['id_cat' => $id_cat,
+                                                'date_maj' => $date_maj,
                                                 'titre' => $new['title'],
-                                                'url' => $this->convertKohaToBokehUrl($this->format_url($new['ext_url'])),
-                                                'tags' => str_replace(', ', ';', $new['tx_danpextendnews_tags']),
+                                                'url' => $url,
+                                                'tags' => $tags,
                                                 'description' => $new['short']]);
 
-      if (!$element->save()) {
+			$element->setCustomField(self::UID_TYPO3_CF, $new['uid']);
+      if (!$element->saveWithCustomFields()) {
         $this->report['sitotheque_errors']++;
-        Class_Import_Typo3_Logs::getInstance()->addErrorRow("site with uid : " . $new['uid'] . ' (' . $new['title'] . ') - ' . implode(', ', $element->getErrors()));
+        Class_Import_Typo3_Logs::getInstance()
+					->addErrorRow("site with uid : " . $new['uid'] . ' (' . $new['title'] . ') - ' . implode(', ', $element->getErrors()));
         return $element;
       }
 
 			$foreign_uids = $this->t3db->findAllForeignUidForNewsCat($new['uid']);
 			$this->sites_categories_map->setDomainsFor($element, $foreign_uids);
 
-			if (in_array(43, array_map(function($row){return $row['uid_foreign'];}, $foreign_uids))) {
+			if ($this->isInTop5($foreign_uids))
 				$this->putSiteInTop5($element, $new);
-			}
+
 			return $element;
 	}
 
 
+	protected function isInTop5($foreign_uids) {
+		return in_array(43, array_map(function($item) { return $item['uid_foreign']; },
+																	$foreign_uids));
+	}
+
 
 	public function putSiteInTop5($element, $t3record) {
 		$parts = $element->getCategorie()->getPathParts();
@@ -197,14 +261,14 @@ class Class_Import_Typo3 {
 	}
 
 
-	public function manipulate_body($body,$image='') {
+	public function manipulate_body($body, $image='') {
 		$body = $this->wrapWithHtml($body);
 		$body = $this->addImage($image).$body;
 		$body = $this->translateLinksToAnchor($body);
 		$body = $this->fixImageLinks($body);
 		$body = $this->fixAttachmentsLinks($body);
 		$body = $this->fixFileAdminLinks($body);
-		return str_replace(["\r\n", "\n\r","\n","\r"],"<br />",$body);
+		return str_replace(["\r\n", "\n\r", "\n","\r"], "<br />", $body);
 	}
 
 
@@ -230,6 +294,7 @@ class Class_Import_Typo3 {
 		return $this->replaceUserfilesLinkPath($body,'fileadmin\/user_upload\/',self::BOKEH_FILEADMIN_URL);
 	}
 
+
 	protected function replaceUserfilesLinkPath($body,$source, $dest) {
 		$regs= '/(< *(a|img)[^>]*(href|src) *= *["\'])(http:\/\/[^"\']*\/)?'.$source.'([^"\']*)/i';
 		return preg_replace($regs, '$1'.$dest.'$5', $body);
@@ -237,11 +302,14 @@ class Class_Import_Typo3 {
 
 
 	protected function translateLinksToAnchor($content) {
-		while((false !== ($start = strpos($content, '<link '))) && (false !== ($end = strpos($content, '</link>')))) {
+		while((false !== ($start = strpos($content, '<link ')))
+					&& (false !== ($end = strpos($content, '</link>')))) {
 			if(false === ($link = substr($content, $start, $end - $start + 7)))
 				return $content;
+
 			$content = str_replace($link, $this->linkToAnchor($link), $content);
 		}
+
 		return $content;
 	}
 
@@ -266,8 +334,9 @@ class Class_Import_Typo3 {
 		return '<a href="' . $url . '">' . $this->getContentFromLink($link) . '</a>';
 	}
 
+
 	protected function convertKohaToBokehUrl($url) {
-		if (false === strpos($url,'http://koha.mediathequeouestprovence.fr/'))
+		if (false === strpos($url, 'http://koha.mediathequeouestprovence.fr/'))
 			return $url;
 
 		if (preg_match('/biblionumber=(\d+)$/', $url, $matches))
@@ -284,6 +353,7 @@ class Class_Import_Typo3 {
 		return $url;
 	}
 
+
 	protected function urlSearchAuthors($url, $search_expression) {
 		return '/miop-test.net/recherche/simple/rech_auteurs/'.$search_expression;
 	}
@@ -293,6 +363,7 @@ class Class_Import_Typo3 {
 		return '/miop-test.net/recherche/simple/expressionRecherche/'.$search_expression;
 	}
 
+
 	protected function urlViewNotice($url, $id_origine) {
 		if (!$exemplaire = Class_Exemplaire::findFirstBy(['id_origine' => $id_origine]))
 			return $url;
@@ -309,82 +380,123 @@ class Class_Import_Typo3 {
 
 
 	protected function wrapWithHtml($content) {
-
-		if('<' === substr($content,0,1))
-			return $content;
-
-		return '<p>' . $content . '</p>';
+		return ('<' === substr($content,0,1)) ?
+			$content : '<p>' . $content . '</p>';
 	}
 
+
 	public function getCatDossierDoc() {
 		return $this->createCategory("Nos dossiers documentaires");
 	}
 
 
 	public function updateCategoriesForDossiersDocumentaires() {
-		$t3_pages = $this->t3db->findAllPagesWithPid(309);
-		foreach ($t3_pages as $page) {
-			$category = $this->createCategory($page['title'],$this->getCatDossierDoc()->getId());
-
-			$contents = $this->t3db->findAllContents($page['uid']);
-			foreach ($contents as $content) {
-				$article = $this->_getArticle($content['uid']);
-				$article->setCategorie($category);
-				$article->save();
-			}
+		$dossiers_doc_id = $this->getCatDossierDoc()->getId();
+		foreach ($this->t3db->findAllPagesWithPid(309) as $page)
+			$this->_addPageInDossiersDocumentaires($page, $dossiers_doc_id);
+	}
+
+
+	protected function _addPageInDossiersDocumentaires($page, $dossiers_doc_id) {
+		if (!$category = $this->createCategory($page['title'], $dossiers_doc_id))
+			return;
+
+		foreach ($this->t3db->findAllContents($page['uid']) as $content)
+			$this->_addContentInDossiersDocumentaires($content, $category);
+	}
+
+
+	protected function _addContentInDossiersDocumentaires($content, $category) {
+		if (!$article = $this->_getArticle($content['uid'])) {
+			Class_Import_Typo3_Logs::getInstance()
+				->addErrorRow('Article with uid: ' . $content['uid'] . ' missing');
+			return;
 		}
 
+		$article->setCategorie($category)
+						->save();
 	}
 
 
 	protected function _getArticle($value) {
-		return Class_Article::findFirstByCustomFieldValue(self::UID_TYPO3_CF,$value);
+		return Class_Article::findFirstByCustomFieldValue(self::UID_TYPO3_CF, $value);
 	}
 
 
+	public function updateArticles($last_import_date) {
+		foreach($this->t3db->findAllArticlesSince($last_import_date) as $new)
+			$this->_updateArticle($new);
 
-  public function importArticles() {
-    $t3news = $this->t3db->findAllArticles();
-    foreach($t3news as $new) {
-			$id_cat = $this->news_categories_map->find($new['category'])->getId();
-			$element = $this->traceUnknownKohaUrls(
-																	function() use ($new, $id_cat){
-																		return $this->createArticle($new, $id_cat);
-																	},
- 																  $new['uid']);
+		Class_Import_Typo3_Logs::getInstance()->setArticlesLog();
+    return $this;
+	}
 
 
-			$this->news_categories_map->setDomainsFor($element,
-																								$this->t3db->findAllForeignUidForNewsCat($new['uid']));
-    }
+	protected function _updateArticle($new) {
+		if ($new['deleted']) {
+			if ($article = $this->_getArticle($new['uid']))
+				$article->deleteWithCustomFields();
+			return;
+		}
+
+		$id_cat = ArticleCategoriesMap::getCategoryOrDefaultCategory($new['category'])
+			->getId();
+
+		$block = function() use ($new, $id_cat){
+			if ($article = $this->_getArticle($new['uid']))
+				return $this->updateArticle($article, $new, $id_cat);
+			return $this->createArticle($new, $id_cat);
+		};
+
+		$this->traceUnknownKohaUrls($block, $new['uid']);
+	}
+
+
+  public function importArticles() {
+    foreach($this->t3db->findAllArticles() as $new)
+			$this->_importArticle($new);
 
 		Class_Import_Typo3_Logs::getInstance()->setArticlesLog();
     return $this;
   }
 
 
-	public function setMiopDateEvent($article,$data) {
-		if ($this->existCategoriesAsForeign($data,self::FOREIGN_UID_DATETIME)) {
+	protected function _importArticle($new) {
+		$id_cat = $this->news_categories_map->find($new['category'])->getId();
+		$element = $this->traceUnknownKohaUrls(
+																					 function() use ($new, $id_cat){
+																						 return $this->createArticle($new, $id_cat);
+																					 },
+																					 $new['uid']);
+
+
+		$this->news_categories_map->setDomainsFor($element,
+																							$this->t3db->findAllForeignUidForNewsCat($new['uid']));
+	}
+
+
+	public function setMiopDateEvent($article, $data) {
+		if ($this->existCategoriesAsForeign($data, self::FOREIGN_UID_DATETIME)) {
 			$converted_date = $this->formatDate($data['datetime']);
 			$article->setEventsDebut($converted_date)->setEventsFin($converted_date);
 		}
 
-		$this->changeCategory($article,$data,$this->getCatDossierDoc()->getId());
+		$this->changeCategory($article, $data, $this->getCatDossierDoc()->getId());
 		return $article;
 	}
 
 
-	public function existCategoriesAsForeign($data,$array_catid) {
-		foreach ($this->t3db->findAllForeignUidForNewsCat($data['uid']) as $domain) {
-			if (in_array($domain['uid_foreign'],$array_catid))
+	public function existCategoriesAsForeign($data, $array_catid) {
+		foreach ($this->t3db->findAllForeignUidForNewsCat($data['uid']) as $domain)
+			if (in_array($domain['uid_foreign'], $array_catid))
 				return true;
-		}
+
 		return false;
 	}
 
 
 	public function changeCategory($article,$data,$id_cat) {
-		if ($this->existCategoriesAsForeign($data,[$id_cat]))
+		if ($this->existCategoriesAsForeign($data, [$id_cat]))
 			$article->setIdCat($this->news_categories_map->find($id_cat)->getId());
 	}
 
@@ -394,37 +506,49 @@ class Class_Import_Typo3 {
 	}
 
 
-	public function createArticle($new,$id_cat) {
+	public function updateArticle($article,$new,$id_cat) {
 		$date_creation = date("Y-m-d H:i:s", $new['crdate']);
 		$debut = $this->formatDate($new['starttime']);
 		$fin = $this->formatDate($new['endtime']);
-
-		$element = Class_Article::newInstance(['date_creation' => $date_creation,
-																					 'debut' => $debut,
-																					 'fin' => $new['hidden'] ? null : $fin,
-																					 'events_debut' => null,
-																					 'events_fin' => null,
-																					 'id_user' => $this->userMap->find($new['cruser_id']),
-																					 'description' => $new['short']? $this->manipulate_body($new['short'],$new['image']): $this->addImage($new['image']),
-																					 'contenu' => $new['bodytext'] ? $this->manipulate_body($new['bodytext'],$new['image']) : '&nbsp;',
-																					 'id_cat' => $id_cat,
-																					 'status' => Class_Article::STATUS_VALIDATED,
-																					 'tags' => str_replace(', ', ';', $new['tx_danpextendnews_tags']),
-																					 'titre' => $new['title']]);
-		$element = $this->setMiopDateEvent($element,$new);
-
-		$element->setUidTypo3($new['uid']);
-		if (!$element->save()) {
-			Class_Import_Typo3_Logs::getInstance()->incrementArticleRejected($element, [$new['uid'],
-																																									$new['title']]);
-			return $element;
-
+		$description = $new['short'] ?
+			$this->manipulate_body($new['short'], $new['image']) :
+			$this->addImage($new['image']);
+
+		$contenu = $new['bodytext'] ?
+			$this->manipulate_body($new['bodytext'], $new['image']) :
+			'&nbsp;';
+
+		$tags = str_replace(', ', ';', $new['tx_danpextendnews_tags']);
+
+		$article->updateAttributes(['date_creation' => $date_creation,
+																'debut' => $debut,
+																'fin' => $new['hidden'] ? null : $fin,
+																'id_user' => $this->userMap->find($new['cruser_id']),
+																'description' => $description,
+																'contenu' => $contenu,
+																'id_cat' => $id_cat,
+																'status' => Class_Article::STATUS_VALIDATED,
+																'tags' => $tags,
+																'titre' => $new['title']]);
+
+		$article = $this->setMiopDateEvent($article,$new);
+		$article->setCustomField('uid_typo3',$new['uid']);
+		if (!$article->saveWithCustomFields()) {
+			Class_Import_Typo3_Logs::getInstance()
+				->incrementArticleRejected($article, [$new['uid'], $new['title']]);
+			return $article;
 		}
 
 		Class_Import_Typo3_Logs::getInstance()->incrementArticlesSaved();
-		return $element;
+		return $article;
 	}
 
+
+	public function createArticle($new,$id_cat) {
+		return $this->updateArticle(new Class_Article(), $new, $id_cat);
+	}
+
+
   private function typo_event_to_date($date, $time) {
     $year = substr($date, 0, 4);
     $month = substr($date, 4, 2);
@@ -444,13 +568,12 @@ class Class_Import_Typo3 {
 
 
   public function importCalendar() {
-    $cal_news = $this->t3db->findAllCalendarEvents();
-    foreach($cal_news as $new) {
-			$this->traceUnknownKohaUrls( function() use ($new) {
-																														return $this->createCalendar($new);
-																													},
-																	 $new['uid']);
-		}
+    foreach($this->t3db->findAllCalendarEvents() as $new)
+			$this->traceUnknownKohaUrls(
+																	function() use ($new) {
+																		return $this->createCalendar($new);
+																	},
+																	$new['uid']);
     return $this;
   }
 
@@ -462,6 +585,11 @@ class Class_Import_Typo3 {
 
       $event_debut = $this->typo_event_to_date($new['start_date'], $new['start_time']);
       $event_fin = $this->typo_event_to_date($new['end_date'], $new['end_time']);
+			$contenu = $this->manipulate_body($new['description'] ?
+																				$new['description'] : $new['title'],
+																				$new['image']);
+
+			$id_cat = $this->cal_categories_map->find($new['category_id'])->getId();
 
       $element = Class_Article::newInstance(['date_creation' => $date_creation,
 																						 'debut' => $debut,
@@ -471,39 +599,61 @@ class Class_Import_Typo3 {
                                              'id_user' => $this->userMap->find($new['cruser_id']),
                                              'all_day' => $new['allday'],
                                              'description' => '',
-                                             'contenu' => $this->manipulate_body($new['description'] ? $new['description'] : $new['title'],$new['image']),
-                                             'id_cat' => $this->cal_categories_map->find($new['category_id'])->getId(),
+                                             'contenu' => $contenu,
+                                             'id_cat' => $id_cat,
                                              'status' => Class_Article::STATUS_VALIDATED,
                                              'tags' => '',
                                              'titre' => $new['title']]);
 
-			$element->setUidTypo3($new['uid']);
-
-      if (!$element->save()) {
+			$element->setCustomField(self::UID_TYPO3_CF,$new['uid']);
+      if (!$element->saveWithCustomFields()) {
         $this->report['calendar_errors']++;
-        Class_Import_Typo3_Logs::getInstance()->addErrorRow('calendar with uid: ' . $new['uid'] . '(' . $new['title'] . ') - ' . implode(', ', $element->getErrors()));
+        Class_Import_Typo3_Logs::getInstance()
+					->addErrorRow('calendar with uid: ' . $new['uid']
+												. '(' . $new['title'] . ') - '
+												. implode(', ', $element->getErrors()));
         return $element;
       }
 
 			$element->setDateCreation($date_creation)->save();
-
       $this->report['calendar_created']++;
-
-			$this->cal_categories_map->setDomainsFor($element,
-																							 $this->t3db->findAllForeignUidForCalendarEventCategory($new['uid']));
+			$this->cal_categories_map
+				->setDomainsFor($element,
+												$this->t3db->findAllForeignUidForCalendarEventCategory($new['uid']));
 			return $element;
-
 	}
 
 
-	public function createCategory($category_name,$id_cat_mere=0) {
-		if ($category=Class_ArticleCategorie::findFirstBy(['libelle' => $category_name]))
+	public function createCategory($category_name, $id_cat_mere=0) {
+		if ($category = Class_ArticleCategorie::findFirstBy(['libelle' => $category_name]))
 			return $category;
-    $category=Class_ArticleCategorie::newInstance(['libelle' => $category_name,'id_cat_mere' =>$id_cat_mere]);
-		$category->save();
-    return $category;
+
+    $category = Class_ArticleCategorie::newInstance(['libelle' => $category_name,'id_cat_mere' =>$id_cat_mere]);
+
+		if ($category->save())
+			return $category;
+
+		return null;
 	}
 
+
+	public function updateArticlePages($update_date) {
+		$pages_cat = Class_ArticleCategorie::findFirstBy(['libelle' => 'Pages fixes']);
+		foreach($this->t3db->findAllContentsSince($update_date) as $new) {
+			$this->traceUnknownKohaUrls(
+																	function() use ($new, $pages_cat){
+																		if ($article = $this->_getArticle($new['uid']))
+																			return $this->updateArticlePage($article,$new,$pages_cat);
+																		return $this->createArticlePage($new, $pages_cat);
+																	},
+				$new['uid']);
+      $this->report['pages_created']++;
+    }
+
+    return $this;
+	}
+
+
   public function importArticlesPages() {
     $rows = $this->t3db->findAllContents();
 
@@ -521,42 +671,49 @@ class Class_Import_Typo3 {
     return $this;
   }
 
-
-	public function createArticlePage($new, $pages_cat) {
+	public function updateArticlePage($article,$new,$pages_cat) {
 		$date_creation = date("Y-m-d H:i:s", $new['crdate']);
 		$debut = $this->formatDate($new['starttime']);
 		$fin = $this->formatDate($new['endtime']);
+		$contenu = $new['bodytext'] ?
+			$this->manipulate_body($new['bodytext'], $new['image'])
+			:'';
 
-		$element = Class_Article::newInstance(['date_creation' => $date_creation,
+		$element = $article->updateAttributes(['date_creation' => $date_creation,
 																					 'debut' => $debut,
 																					 'fin' => $new['hidden'] ? null : $fin,
 																					 'id_user' => $this->userMap->find($new['cruser_id']),
 																					 'description' => '',
-																					 'contenu' => $new['bodytext'] ? $this->manipulate_body($new['bodytext'],$new['image']) :'',
+																					 'contenu' => $contenu,
 																					 'id_cat' => $pages_cat->getId(),
 																					 'status' => Class_Article::STATUS_VALIDATED,
 																					 'tags' => '',
 																					 'titre' => $new['header']]);
 
-
-		if (!$element->save()) {
+		$element->setCustomField(self::UID_TYPO3_CF,$new['uid']);
+		if (!$element->saveWithCustomFields()) {
 			$this->report['pages_errors']++;
-			Class_Import_Typo3_Logs::getInstance()->addErrorRow('pages with uid: ' . $new['uid'] . ' (' . $new['title'] . ') - ' . implode(', ', $element->getErrors()));
+			Class_Import_Typo3_Logs::getInstance()
+				->addErrorRow('pages with uid: ' . $new['uid']
+											. ' (' . $new['title'] . ') - '
+											. implode(', ', $element->getErrors()));
 		}
-		$element->setUidTypo3($new['uid']);
-		$element->save();
+
 		return $element;
 	}
 
 
-	public function traceUnknownKohaUrls($closure,$uid) {
+	public function createArticlePage($new, $pages_cat) {
+		return $this->updateArticlePage(new Class_Article(), $new, $pages_cat);
+	}
+
+
+	public function traceUnknownKohaUrls($closure, $uid) {
 		$this->unknown_koha_urls = [];
 		$element = $closure();
-		foreach($this->unknown_koha_urls as $url) {
-			Class_Import_Typo3_Logs::getInstance()->addUnknownUrl($element,
-																														$url,
-																														$uid);
-		}
+		foreach($this->unknown_koha_urls as $url)
+			Class_Import_Typo3_Logs::getInstance()->addUnknownUrl($element, $url, $uid);
+
 		return $element;
 	}
 
@@ -565,13 +722,12 @@ class Class_Import_Typo3 {
   public function format_url($url) {
     if (!$url = explode(' ', $url)[0])
       return '';
+
     $url = preg_replace(['/^http:\/\//', '/^\/\//'], '', trim(strtolower($url)));
     return (0 !== strpos('http', $url)) ? 'http://'.$url : $url;
   }
 
 
-
-
   public function reset_auto_increment() {
     Zend_Registry::get('sql')->execute('alter table cms_article AUTO_INCREMENT=1');
     Zend_Registry::get('sql')->execute('alter table cms_categorie AUTO_INCREMENT=1');
@@ -583,67 +739,57 @@ class Class_Import_Typo3 {
 }
 
 
-class UserMap {
-
 
+class UserMap {
 	protected $map = [];
-	protected $saved = 0;
-	protected $updated = 0;
-	protected $errors = [];
-	protected $t3users = 0;
 
-
-	public function __construct() {
+	public function init() {
 		$where = 'ROLE_LEVEL < ' . ZendAfi_Acl_AdminControllerRoles::ADMIN_PORTAIL; // exclude ADMIN.
 		$where .= ' AND ROLE_LEVEL <> ' . ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB; // exclude SIGB members.
-
     Class_Users::deleteBy(['where' => $where]);
 	}
 
 
-	public function updateUser($data, &$user) {
-		$user->setNom($data['realName']);
-		$user->setMail($data['email']);
+	public function updateUser($data, $user) {
+		$user->setNom($data['realName'])
+				 ->setMail($data['email'])
+				 ->setPassword('achanger');
 	}
 
 
 	public function newUser($data) {
-		Class_Import_Typo3_Logs::getInstance()->incrementT3Users();
-			$user;
-			$updated = 0;
-			if ($user = Class_Users::findFirstBy(['login'=> $data['username']])) {
-				$updated = 1;
-				$this->updateUser($data, $user);
-			}
-			else {
-				$user = Class_Users::newInstance(['nom' => $data['realName'],
-																					'mail' => $data['email'],
-																					'login' => $data['username'],
-																					'password' => 'achanger']);
-			}
+		$logs = Class_Import_Typo3_Logs::getInstance();
+		$logs->incrementT3Users();
 
-			if ($data['admin'] == '1') {
-				$user->beAdminPortail();
-			}
-			else {
-				$user->changeRoleTo(ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL);
-			}
+		$user = $this->_findOrCreate($data['username']);
+		$updated = !$user->isNew();
+		$this->updateUser($data, $user);
 
-			if (!$user->save())
-				return Class_Import_Typo3_Logs::getInstance()->incrementRejected($user, $data);
+		($data['admin'] == '1') ?
+			$user->beAdminPortail() :
+			$user->changeRoleTo(ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL);
+
+		if (!$user->save()) {
+			$logs->incrementRejected($user, $data);
+			return;
+		}
 
-			$updated
-				? Class_Import_Typo3_Logs::getInstance()->incrementUpdated()
-				: Class_Import_Typo3_Logs::getInstance()->incrementSaved();
+		$updated
+			? $logs->incrementUpdated()
+			: $logs->incrementSaved();
 
-			$this->map[$data['uid']] = $user->getId();
+		$this->map[$data['uid']] = $user->getId();
+	}
+
+
+	protected function _findOrCreate($login) {
+		return ($user = Class_Users::findFirstBy(['login' => $login])) ?
+			$user : Class_Users::newInstance(['login' => $login]);
 	}
 
 
 	public function find($uid) {
-    return  isset($this->map[$uid])
-      ? $this->map[$uid]
-      : 0;
+    return isset($this->map[$uid]) ? $this->map[$uid] : 0;
 	}
 }
 
@@ -679,12 +825,15 @@ abstract class CategoriesMap {
       $cat = $this->map[$t3id];
       return $cat->getId();
     }
+
     return  0;
   }
 
+
   public function newCategory($title, $t3uid, $t3pid) {
     $category = $this->_buildNewCategory($title, $this->getParentCatId($t3pid));
-    if(!$category->save())
+		$category->setCustomField(Class_Import_Typo3::UID_TYPO3_CF,$t3uid);
+    if(!$category->saveWithCustomFields())
 			return $this->addError($category, $title, $t3uid, $t3pid);
 
 		$this->incrementSaved();
@@ -702,6 +851,40 @@ abstract class CategoriesMap {
 		}
 	}
 
+
+	public static function getOrCreateDefaultCategory() {
+		if ($category = Class_ArticleCategorie::findFirstBy(['libelle' => 'Non classé']))
+			return $category;
+
+    $cat = Class_ArticleCategorie::newInstance(['libelle' => 'Non classé',
+																								'id_cat_mere' => 0]);
+		$cat->save();
+		return $cat;
+
+	}
+
+
+	public static function getCategory($uid) {
+		return Class_ArticleCategorie::findFirstByCustomFieldValue(Class_Import_Typo3::UID_TYPO3_CF, $uid);
+	}
+
+
+	public static function getCategoryOrDefaultCategory($uid) {
+		return ($category = self::getCategory($uid)) ?
+			$category : self::getOrCreateDefaultCategory();
+	}
+
+
+	public function fixParentCategory($t3uid, $t3pid) {
+		$category = self::getCategory($t3uid);
+		if ($category->getId() == $this->default_cat->getId())
+			return;
+
+		$category->setParentCategorie(self::getCategory($t3pid))
+						 ->save();
+	}
+
+
 	public function createDomainMap() {
 		foreach($this->map as $category)
 			$this->domaine_map->findOrCreateDomaine($category);
@@ -714,7 +897,7 @@ abstract class CategoriesMap {
 
 
   public function find($t3id) {
-    return  isset($this->map[$t3id])
+		return isset($this->map[$t3id])
       ? $this->map[$t3id]
       : $this->default_cat;
   }
@@ -724,12 +907,12 @@ abstract class CategoriesMap {
 		$domains = [];
 		foreach ($t3_domain_ids as $t3_domain) {
 			$category = $this->find($t3_domain['uid_foreign']);
-			$domains[] = $this->domaine_map->findOrCreateDomaine($category);
+			$domains[] = $this->domaine_map
+				->findOrCreateDomaine($category,$t3_domain['uid_foreign']);
 		}
 
-		if (isset($category)) {
+		if (isset($category))
 			$model->setCategorie($category);
-		}
 
 		$model->setDomaines($domains)->save();
 	}
@@ -740,7 +923,7 @@ abstract class CategoriesMap {
 class DomaineMap {
   protected $map = [];
 
-  public function findOrCreateDomaine($category) {
+  public function findOrCreateDomaine($category, $uid=0) {
     if (!$category)
       return null;
 
@@ -750,10 +933,14 @@ class DomaineMap {
       return $this->map[$path];
 
     $parent_domaine = $this->findOrCreateDomaine($category->getParentCategorie());
+
     $catalogue = Class_Catalogue::newInstance(['libelle' => $category->getLibelle(),
                                                'parent_id' => $parent_domaine ? $parent_domaine->getId() : 0]);
 
-		if (!$catalogue->save()) {
+		if (!$uid)
+			$catalogue->setCustomField(Class_Import_Typo3::UID_TYPO3_CF, $uid);
+
+		if (!$catalogue->saveWithCustomFields()) {
 			Class_Import_Typo3_Logs::getInstance()->incrementDomainsRejected($catalogue);
 			return;
 		}
@@ -764,19 +951,16 @@ class DomaineMap {
 }
 
 
-class ArticleCategoriesMap  extends CategoriesMap {
+class ArticleCategoriesMap extends CategoriesMap {
   protected function _buildNewCategory($libelle, $parent_id=0) {
-    $cat =  Class_ArticleCategorie::newInstance(['libelle' => $libelle,
-                                                 'id_cat_mere' => $parent_id]);
-    /* if ($double_cat = $this->findByPath($cat->getPath)) */
-    /*  return $double_cat; */
-    /* $this->path_map [] = $cat; */
-    return $cat;
+    return Class_ArticleCategorie::newInstance(['libelle' => $libelle,
+																								'id_cat_mere' => $parent_id]);
   }
 
 
 	protected function addError($category, $title, $t3uid, $t3pid) {
-		return Class_Import_Typo3_Logs::getInstance()->incrementArticleCategoriesRejected($category, $title, $t3uid, $t3pid);
+		return Class_Import_Typo3_Logs::getInstance()
+			->incrementArticleCategoriesRejected($category, $title, $t3uid, $t3pid);
 	}
 
 
@@ -786,7 +970,7 @@ class ArticleCategoriesMap  extends CategoriesMap {
 }
 
 
-class SiteCategoriesMap  extends CategoriesMap {
+class SiteCategoriesMap extends CategoriesMap {
   protected function _buildNewCategory($libelle, $parent_id=0) {
     return Class_SitothequeCategorie::newInstance(['libelle' => $libelle,
                                                    'id_cat_mere' => $parent_id]);
@@ -794,7 +978,8 @@ class SiteCategoriesMap  extends CategoriesMap {
 
 
 	protected function addError($category, $title, $t3uid, $t3pid) {
-		return Class_Import_Typo3_Logs::getInstance()->incrementSitoCategoriesRejected($category, $title, $t3uid, $t3pid);
+		return Class_Import_Typo3_Logs::getInstance()
+			->incrementSitoCategoriesRejected($category, $title, $t3uid, $t3pid);
 	}
 
 
@@ -803,7 +988,6 @@ class SiteCategoriesMap  extends CategoriesMap {
 	}
 
 
-
 	public function findOrCreateByPath($path) {
 		if ($path == Trait_TreeNode::$PATH_SEPARATOR)
 			return null;
@@ -811,14 +995,20 @@ class SiteCategoriesMap  extends CategoriesMap {
 		$parts = array_values(array_filter(explode(Trait_TreeNode::$PATH_SEPARATOR, $path)));
 
 		$category = null;
-		foreach($parts as $part) {
-			if (!$sub_category = Class_SitothequeCategorie::findFirstBy(['libelle' => $part,
-																																	 'id_cat_mere' => $category ? $category->getId() : 0])) {
-				$sub_category = Class_SitothequeCategorie::newInstance(['libelle' => $part,
-																														'id_cat_mere' => $category ? $category->getId() : 0]);
-				$sub_category->save();
-			}
-			$category = $sub_category;
+		foreach($parts as $part)
+			$category = $this->_findOrCreateUnder($part, $category);
+
+		return $category;
+	}
+
+
+	protected function _findOrCreateUnder($label, $parent) {
+		$attribs = ['libelle' => $label,
+								'id_cat_mere' => $parent ? $parent->getId() : 0];
+
+		if (!$category = Class_SitothequeCategorie::findFirstBy($attribs)) {
+			$category = Class_SitothequeCategorie::newInstance($attribs);
+			$category->save();
 		}
 
 		return $category;
@@ -841,8 +1031,6 @@ class Typo3DB {
 		$t3db,
 		$pages_titles;
 
-
-
 	public function __construct() {
     $this->t3db = new Class_Systeme_Sql('','','','');
 		$this
@@ -852,7 +1040,8 @@ class Typo3DB {
 																		['host' => 'localhost',
 																		 'username' => 'root',
 																		 'password' => 'root',
-																		 'dbname' =>  'miop_typo3']));
+//																		 'dbname' =>  'miop_typo3']));
+																		 'dbname' =>  'miopencoding']));
 	}
 
 
@@ -860,11 +1049,10 @@ class Typo3DB {
 		if (isset($this->pages_titles[$uid]))
 			return $this->pages_titles[$uid];
 
-		if (!$row = $this->t3db->fetchEnreg('select title from pages where uid='.$uid)) {
-			return $this->pages_titles[$uid] = '';
-		}
+		$title = ($row = $this->t3db->fetchEnreg('select title from pages where uid=' . $uid)) ?
+			$row['title'] : '';
 
-		return $this->pages_titles[$uid] = $row['title'];
+		return $this->pages_titles[$uid] = $title;
 	}
 
 
@@ -877,26 +1065,47 @@ class Typo3DB {
 		return $this->t3db->fetchAll('select * from be_users where uid > 1');
 	}
 
+
 	public function findAllNewsCat() {
 		return $this->t3db->fetchAll('select * from tt_news_cat where deleted=0 order by uid ASC');
 	}
 
+
+	public function findAllNewsCatSince($update_date) {
+		return $this->t3db->fetchAll('select * from tt_news_cat where deleted=0 and  tstamp >='.$update_date.' order by uid ASC');
+	}
+
+
 	public function findAllEventCat() {
 		return $this->t3db->fetchAll("select * from tx_cal_category where deleted=0 order by uid");
 	}
 
+
+	public function findAllEventCatSince($update_date) {
+		return $this->t3db->fetchAll("select * from tx_cal_category where deleted=0 and tstamp >=".$update_date." order by uid");
+	}
+
+
 	public function findAllSites() {
 		return $this->t3db->fetchAll("select * from tt_news where deleted=0 and hidden=0 and ext_url>'' order by uid ASC");
 	}
 
+
+	public function findAllArticlesSince($last_import_date) {
+		return $this->t3db->fetchAll("select * from tt_news where hidden=0 and ext_url='' and tstamp >= ".$last_import_date."  order by uid ASC");
+	}
+
+
 	public function findAllArticles() {
 		return $this->t3db->fetchAll("select * from tt_news where deleted=0 and hidden=0 and ext_url='' order by uid ASC");
 	}
 
+
 	public function findAllForeignUidForNewsCat($uid) {
 		return $this->t3db->fetchAll("select distinct uid_foreign from tt_news_cat_mm where uid_local=". $uid ." order by sorting");
 	}
 
+
 	public function findAllForeignUidForCalendarEventCategory($uid) {
 		return $this->t3db->fetchAll("select distinct uid_foreign from tx_cal_event_category_mm where uid_local=" . $uid . " order by sorting");
 	}
@@ -906,11 +1115,19 @@ class Typo3DB {
 		return $this->t3db->fetchAll("select * from tx_cal_event where deleted=0 and hidden=0 order by uid ASC");
 	}
 
+
 	public function findAllContents($page_id=false) {
 		$pid_sql='';
 		if ($page_id)
 			$pid_sql='and pid='.$page_id;
+
 		return $this->t3db->fetchAll("select * from tt_content where deleted=0 and hidden=0 and header>'' and bodytext>'' and  (ctype='text' or ctype='textpic') ".$pid_sql." order by uid ASC");
 	}
+
+
+	public function findAllContentsSince($update_date) {
+		return $this->t3db->fetchAll("select * from tt_content where deleted=0 and tstamp>=".$update_date." and hidden=0 and header>'' and bodytext>'' and  (ctype='text' or ctype='textpic') order by uid ASC");
+	}
+
 }
 ?>
\ No newline at end of file
diff --git a/library/Class/Sitotheque.php b/library/Class/Sitotheque.php
index 811e21f95296ac1fdcaa445284201fee26e1c8ae..2dae95d5f2915995671a52cb087cc470a8ea8f18 100644
--- a/library/Class/Sitotheque.php
+++ b/library/Class/Sitotheque.php
@@ -99,9 +99,9 @@ class SitothequeLoader extends Storm_Model_Loader {
 }
 
 
-
 class Class_Sitotheque extends Storm_Model_Abstract {
-	use Trait_Translator, Trait_TreeViewableItem, Trait_HasManyDomaines, Trait_Indexable;
+	use Trait_Translator, Trait_TreeViewableItem, Trait_HasManyDomaines, Trait_Indexable, Trait_CustomFields;
+
 
 	protected $_loader_class = 'SitothequeLoader';
 	protected $_table_name = 'sito_url';
diff --git a/library/Class/SitothequeCategorie.php b/library/Class/SitothequeCategorie.php
index 13b0a38141f3996d79b4871ae36931983c5a32df..0fcf189d8fc6e969593f8f4ca69485bddfeeef75 100644
--- a/library/Class/SitothequeCategorie.php
+++ b/library/Class/SitothequeCategorie.php
@@ -20,7 +20,7 @@
  */
 class Class_SitothequeCategorie extends Storm_Model_Abstract {
  	use Trait_TreeViewableCategorie, Trait_Translator, Trait_TreeNode;
-//	use Trait_CustomFields;
+	use Trait_CustomFields;
 	protected $_table_name = 'sito_categorie';
 	protected $_table_primary = 'ID_CAT';
 	protected $_belongs_to = ['parent_categorie' => ['model' => 'Class_SitothequeCategorie',
diff --git a/library/Trait/CustomFields.php b/library/Trait/CustomFields.php
index fc7878db1020c3ab8445ad6c14292b30475f4505..fb029e77a91279d6654431e94d4aa860193facee 100644
--- a/library/Trait/CustomFields.php
+++ b/library/Trait/CustomFields.php
@@ -19,81 +19,19 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
-
-/**
- * To use this Trait in a model  you need to :
- * Register you model : cf Class_CustomField_Model::register
- * Redefine this 2 methods :
-	public function _set($field, $value) {
-    	return $this->_setCustomField($field,$value);
-	}
-
-	public function _get($field) {
-	    return  $this->_getCustomField($field);
-  }
-
- *	WARN : this trait redefine afterSave() and beforeSave() method
- *
- */
-
-
-
 trait Trait_CustomFields {
 	protected $custom_fields=[],
 		$custom_fields_meta;
 
-	public static  function findMetaForLabel($label) {
-		return Class_CustomField_Meta::findFirstBy(['label' => $label]);
-	}
-
-	public static function findFirstByCustomFieldValue($custom_field_name,$custom_field_value) {
-		$meta=self::findMetaForLabel($custom_field_name);
-		$custom_fields=Class_CustomField::findAllBy(['meta_id' => $meta->getId(),
-																								 'model' => static::getModelName()]);
-
-		foreach ($custom_fields as $custom_field) {
-			$value = Class_CustomField_Value::findFirstBy(['custom_field_id' => $custom_field->getId(),
-																										 'value' => $custom_field_value]);
-			if ($value)
-				return static::getLoader()->find($value->getModelId());
-		}
-		return null;
-
+	public static function findFirstByCustomFieldValue($name, $value) {
+		$model = Class_CustomField_Model::getModel(static::getModelName());
+		return $model->findFirstByCustomFieldValue($name, $value);
 	}
 
 
-	public static function getMeta($custom_field_name) {
-		if ($meta=Class_CustomField_Meta::findFirstBy(['label' => $custom_field_name]))
-			return $meta;
-
-	}
-
-
-	public static function getAndCreateMeta($custom_field_name,$custom_field_type,$options='') {
-		if ($meta=self::getMeta($custom_field_name))
-			return $meta;
-		$meta=Class_CustomField_Meta::newInstance(
-																							[
-																							 'label' => $custom_field_name,
-																							 'field_type' => $custom_field_type,
-																							 'options_list' => $options]);
-		$meta->save();
-
-		return $meta;
-	}
-
-
-	public static function addCustomField($custom_field_name,$custom_field_type,$options='') {
-		$meta=self::getAndCreateMeta($custom_field_name,$custom_field_type,$options);
-		if ($custom_field_model=Class_CustomField::findFirstBy(['meta_id' => $meta->getId(),
-																														'model' => self::getModelName()]))
-			return $custom_field_model;
-		$custom_field_article=Class_CustomField::newInstance(['meta_id' => $meta->getId(),
-																													'priority' => 1,
-																													'model' => self::getModelName()]);
-		$custom_field_article->save();
-		return $custom_field_article;
-
+	public static function addCustomField($name, $type, $options='') {
+		Class_CustomField_Model::getModel(static::getModelName())
+			->addField($name, $type, $options);
 	}
 
 
@@ -102,109 +40,47 @@ trait Trait_CustomFields {
 	}
 
 
-	public function isRegistered() {
-		return  Class_CustomField_Model::isRegistered($this->getModelName());
-	}
-
-
-	public function getAvailableMeta() {
-		$availables_meta = [];
-		$custom_fields_meta = Class_CustomField_Meta::findAll();
+	public function getCustomField($name) {
+		if (isset($this->custom_fields[$name]))
+			return $this->custom_fields[$name];
+		if ($this->isNew())
+			return '';
+		$model_values = Class_CustomField_Model::getModel($this->getModelName())->find($this->getId());
 
-		foreach($custom_fields_meta as $custom_field_meta) {
-			$custom_fields = Class_CustomField::findAllBy(['meta_id' => $custom_field_meta->getId(),
-																										 'model' => $this->getModelName()]);
-			if ($custom_fields)
-				$availables_meta[] = $custom_field_meta;
-
-		}
-
-		return $availables_meta;
-
-	}
-
-
-
-	public function afterSave() {
-		if (!$this->isRegistered())
-			return true;
-
-		foreach ($this->custom_fields as $field => $value) {
-
-			if (!$meta =self::getMeta($field))
-				continue;
-			$custom_field=Class_CustomField::findFirstBy(['meta_id' => $meta->getId(),
-																										'model'=> $this->getModelName()]);
-
-			if (!$cf_value = Class_CustomField_Value::findFirstBy(['model_id' => $this->getId(),
-																														 'custom_field_id'=> $custom_field->getId()]))
-				$cf_value = Class_CustomField_Value::newInstance(['model_id' => $this->getId() ,
-																													'custom_field_id' =>$custom_field->getId()]);
-
-			return 	$cf_value->setValue($value)->save();
-		}
-	}
-
-
-	public function findCustomFieldValue($custom_field_name) {
-		$meta=self::findMetaForLabel($custom_field_name);
-		$custom_field=Class_CustomField::findFirstBy(['meta_id' => $meta->getId(),
-																									'model' => $this->getModelName()]);
-
-		$values = Class_CustomField_Value::findAllBy(['custom_field_id' => $custom_field->getId(),
-																									'model_id' => $this->getId()]);
-
-		foreach ($values as $value) {
+		if ($value = $model_values->getFieldValueByName($name))
 			return $value->getValue();
-		}
 		return '';
-
 	}
 
 
-	public function getCustomFieldsAvailable() {
-		if (!$custom_field_model=Class_CustomField_Model::getModel($this->getModelName()))
-			return [];
-		return $custom_field_model->getItems();
+	public function setCustomField($field,$value) {
+		$this->custom_fields[$field]=$value;
+		return $this;
 	}
 
 
-	public function getCustomMetaNames() {
-		if (!$this->isRegistered())
-			return [];
-		if ($this->custom_meta_names)
-			return $this->custom_meta_names;
-
-		return $this->custom_meta_name=array_map(function($meta) {return $meta->getLabel();},$this->getAvailableMeta());
-
-	}
-
-	public function _setCustomField($field,$value) {
-		if (in_array($field,$this->getCustomMetaNames()))
-			return $this->custom_fields[$field]=$value;
-		return parent::_set($field, $value);
-
-	}
+	public function saveWithCustomFields() {
+		if (!$this->save())
+			return false;
 
+		if (!Class_CustomField_Model::isRegistered($this->getModelName()))
+			return true;
 
-	public function _getCustomField($field) {
-		if ($this->isAttributeExists($field))
-			return parent::_get($field);
+		$model_values = Class_CustomField_Model::getModel($this->getModelName())->find($this->getId());
 
-		if(!$meta =self::getMeta($field))
-			return null;
+		foreach ($this->custom_fields as $key => $value)
+			$model_values->setFieldValueByName($key, $value);
 
-		if (isset($this->custom_fields[$field]))
-			return $this->custom_fields[$field];
-		$this->custom_fields[$field]=$this->findCustomFieldValue($field);
-		return $this->custom_fields[$field];
+		$model_values->save();
+		return true;
 	}
 
 
-	public function afterDelete() {
-		if (!$this->isRegistered())
-			return true;
-		Class_CustomField_Value::deleteBy(['model_id' => $this->getId()]);
+	public function deleteWithCustomFields() {
+		if (Class_CustomField_Model::isRegistered($this->getModelName())
+				&& $model_values = Class_CustomField_Model::getModel($this->getModelName())->find($this->getId()))
+			$model_values->deleteValues();
+		$this->delete();
 	}
 }
 ?>
\ No newline at end of file
diff --git a/scripts/import_typo3.php b/scripts/import_typo3.php
index 442bb38a5f0ca9ea40dd17a85bfd0a7f20a2dcad..07068d665db6b1a25005e0a0f028bdd7b6ca101a 100644
--- a/scripts/import_typo3.php
+++ b/scripts/import_typo3.php
@@ -2,8 +2,8 @@
 /*
  * Launch import_typo3.php like:
  *    php import_typo3.php <arg>
- *    <arg> can be users (import users only), articles (import articles only), all (import all)
- *          or update (don't destroy database)
+ *    <arg> can be users (import users only), docu(update dossiers documentaires only), articles (import articles only) or all (import all)
+ *   php import_typo3.php update <last_update_date 20-11-2015 >
  * Script import data in a database named miop_typo3. To change it, edit the line 109.
  */
 
@@ -13,9 +13,21 @@ $toRun = $argv[1];
 
 Class_Import_Typo3_Logs::getInstance()->activateOutput();
 Class_CustomField_Model::registerAll([
-																			new Class_CustomField_ModelConfiguration_Article()
-																			]);
+																			new Class_CustomField_ModelConfiguration_Article(),
+																			new Class_CustomField_ModelConfiguration_Sitotheque(),
+																			new Class_CustomField_ModelConfiguration_SitothequeCategorie(),
+																			new Class_CustomField_ModelConfiguration_Catalogue(),
+																			new Class_CustomField_ModelConfiguration_ArticleCategorie()]);
 
 $migration = new Class_Import_Typo3();
-$migration->run($toRun);
+
+if ($toRun=="update" && sizeof($argv)<3) {
+	echo "Missing last update date\n";
+	return;
+}
+
+if (sizeof($argv)>2)
+	return $migration->run($toRun,$argv[2]);
+
+return $migration->run($toRun);
 ?>
\ No newline at end of file
diff --git a/scripts/utf8miop.sql b/scripts/utf8miop.sql
new file mode 100644
index 0000000000000000000000000000000000000000..aea0ca5e648daf1d28807d951deff8893d3bd478
--- /dev/null
+++ b/scripts/utf8miop.sql
@@ -0,0 +1,12 @@
+UPDATE tt_content SET short = CONVERT(CAST(CONVERT(short USING latin1) AS binary) USING utf8); 
+UPDATE tt_news SET bodytext = CONVERT(CAST(CONVERT(bodytext USING latin1) AS binary) USING utf8);
+UPDATE tt_news SET short = CONVERT(CAST(CONVERT(short USING latin1) AS binary) USING utf8);                                                                                      
+UPDATE tt_news SET category = CONVERT(CAST(CONVERT(category USING latin1) AS binary) USING utf8);                                                                                      
+
+ UPDATE tt_content SET bodytext = CONVERT(CAST(CONVERT(bodytext USING latin1) AS binary) USING utf8);                                                                             
+ UPDATE pages  SET title = CONVERT(CAST(CONVERT(title USING latin1) AS binary) USING utf8);                                                                                                                
+ UPDATE tt_news_cat  SET title = CONVERT(CAST(CONVERT(title USING latin1) AS binary) USING utf8);                                                                                                                
+ UPDATE tt_news  SET title = CONVERT(CAST(CONVERT(title USING latin1) AS binary) USING utf8);                                                                                                              
+ UPDATE tt_content  SET title = CONVERT(CAST(CONVERT(title USING latin1) AS binary) USING utf8);    
+ UPDATE tx_cal_category  SET title = CONVERT(CAST(CONVERT(title USING latin1) AS binary) USING utf8);    
+
diff --git a/tests/application/modules/admin/controllers/CmsControllerTest.php b/tests/application/modules/admin/controllers/CmsControllerTest.php
index cd26de9013fadef942b00a47ce70ea904eb04661..8401f015acbe9b13cb4074ae9821cecac33a70d1 100644
--- a/tests/application/modules/admin/controllers/CmsControllerTest.php
+++ b/tests/application/modules/admin/controllers/CmsControllerTest.php
@@ -31,10 +31,6 @@ abstract class CmsControllerTestCase extends Admin_AbstractControllerTestCase {
 		Storm_Model_Loader::defaultToVolatile();
 		$this->setupBib();
 
-		Class_Exemplaire::beVolatile();
-		Class_CustomField::beVolatile();
-		Class_CustomField_Meta::beVolatile();
-
 		$this->fixture('Class_UserGroup', ['id' => 22,
 																			 'libelle' => 'Testing group']);
 
@@ -2618,6 +2614,8 @@ class CmsControllerEditArticleWithDate30December2014Test extends CmsControllerte
 		parent::setup();
 		$this->concert->setFin('2014-12-30');
 
+		Class_Users::getIdentity()->setRoleLevel(ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN);
+
 		$this->dispatch('/admin/cms/edit/id/4');
 	}
 
diff --git a/tests/library/Class/Import/Typo3Fixture.php b/tests/library/Class/Import/Typo3Fixture.php
index 034fa0c04c63590a75fc5dd35ee76f70cc58f34f..7c2e00d7bbda184c800d844dbf99f1243c1a69e1 100644
--- a/tests/library/Class/Import/Typo3Fixture.php
+++ b/tests/library/Class/Import/Typo3Fixture.php
@@ -22,33 +22,46 @@
 class MockTypo3DB {
 
 	public function findAllUsers() {
-		return [ ['uid' => 20,
-							'username' => 'toto',
-							'realName' => 'toto',
-							'email' => 'toto@null.com',
-							'admin' => 1
-			],
+		return [['uid' => 20,
+						 'username' => 'toto',
+						 'realName' => 'toto',
+						 'email' => 'toto@null.com',
+						 'admin' => 1],
+
 						['uid' => 21,
 						 'username' => 'jean',
 						 'realName' => 'Jean Jean',
 						 'email' => 'jean-jeantoto@null.com',
-						 'admin' => 0
-						],
+						 'admin' => 0],
+
 						['uid' => 43,
 						 'username' => 'sserge',
 						 'realName' => 'Serge Serge',
 						 'email' => 'serge@null.com',
-						 'admin' => 0
-						],
+						 'admin' => 0],
+
 						['uid' => 123456789,
 						 'username' => null,
 						 'realName' => 'Tom',
 						 'email' => null,
-						 'admin' => 0
-						]
+						 'admin' => 0]];
+	}
+
+	public function findAllNewsCatSince($update_date) {
+		return [ ['title' => 'Jeux',
+						 'uid' => 777,
+						 'parent_category' => 99
+			],
+				['title' => 'd\'hiver',
+						 'uid' => 81,
+						 'parent_category' => 99
+						],
+
 		];
+
 	}
 
+
 	public function findAllNewsCat() {
 		return [
 						['title' => 'My category',
@@ -93,6 +106,17 @@ class MockTypo3DB {
 						]];
 	}
 
+	public function findAllEventCatSince($update_date) {
+		return [
+						['uid' => 30,
+						 'title' => 'New Category',
+						 'parent_category' => 0
+						],
+];
+
+
+	}
+
 
 	public function findAllEventCat() {
 		return [
@@ -144,6 +168,20 @@ class MockTypo3DB {
 	}
 
 
+	public function findAllArticlesSince($last_import_date) {
+		$articles = $this->findAllArticles();
+		$articles[5]['uid']=666;
+		$articles[5]['short']='Crash';
+		$articles[5]['title']='Crash Test';
+		$articles[1]['deleted']=1;
+		$articles[0]['title']='Tous à bord du bateau pirate';
+		$articles[0]['category']=777;
+		$articles[0]['bodytext']="MODIFY".$articles[0]['bodytext'];
+		$articles[4]['bodytext']="MODIFIED".$articles[4]['bodytext'];
+		return [$articles[0],$articles[1], $articles[5], $articles[4]];
+	}
+
+
 	public function findAllArticles() {
 		return [ [
 							'uid' => 14474,
@@ -151,7 +189,7 @@ class MockTypo3DB {
 							'cruser_id' => 43,
 							'starttime' => 1415110980,
 							'endtime' => 1422973380,
-							'hidden' => 0,
+							'deleted' => 0,'hidden' => 0,
 							'short' => 'A bord.',
 							'category' => 10,
 							'image' =>  'bateau.jpg',
@@ -185,7 +223,7 @@ class MockTypo3DB {
 						[ 'uid' => 14476,
 						 'starttime' => 0,
 						 'endtime' => 0,
-						 'hidden' => 0,
+						 'deleted' => 0,'hidden' => 0,
 						 'crdate' => 1359562198,
 						 'cruser_id' => 22,
 						 'short' => null,
@@ -210,7 +248,7 @@ La collection<span style="text-decoration: none"><span style="font-style: normal
 						[ 'uid' => 14477,
 						 'starttime' => 1419844200,
 						 'endtime' => 1420017000,
-						 'hidden' => 0,
+						 'deleted' => 0,'hidden' => 0,
 						 'datetime' =>1419933840,
 						 'crdate' => 1419933840,
 						 'cruser_id' => 22,
@@ -225,7 +263,7 @@ La collection<span style="text-decoration: none"><span style="font-style: normal
 						[ 'uid' => 14478,
 						 'starttime' => 0,
 						 'endtime' => 0,
-						 'hidden' => 0,
+						 'deleted' => 0,'hidden' => 0,
 						 'image' => 'onyx.png',
 						 'crdate' => 1359562208,
 						 'cruser_id' => 22,
@@ -237,7 +275,7 @@ La collection<span style="text-decoration: none"><span style="font-style: normal
 					[ 'uid' => 14488,
 						 'starttime' => 0,
 						 'endtime' => 0,
-						 'hidden' => 0,
+						 'deleted' => 0,'hidden' => 0,
 						 'crdate' => 1357562208,
 						 'datetime' => 1395409080,
 						 'cruser_id' => 22,
@@ -250,7 +288,7 @@ La collection<span style="text-decoration: none"><span style="font-style: normal
 						[ 'uid' => 14888,
 						 'starttime' => 0,
 						 'endtime' => 0,
-						 'hidden' => 0,
+						 'deleted' => 0,'hidden' => 0,
 						 'crdate' => 1357562208,
 						 'cruser_id' => 22,
 						 'short' => null,
@@ -262,7 +300,7 @@ La collection<span style="text-decoration: none"><span style="font-style: normal
 						['uid' => 84888,
 						 'starttime' => 0,
 						 'endtime' => 0,
-						 'hidden' => 0,
+						 'deleted' => 0,'hidden' => 0,
 						 'image' => '',
 						 'crdate' => 1357592208,
 						 'cruser_id' => 22,
@@ -276,7 +314,7 @@ La collection<span style="text-decoration: none"><span style="font-style: normal
 						['uid' => 123,
 						 'starttime' => 0,
 						 'endtime' => 0,
-						 'hidden' => 0,
+						 'deleted' => 0,'hidden' => 0,
 						 'crdate' => 1357592258,
 						 'cruser_id' => 22,
 						 'short' => null,
@@ -289,7 +327,7 @@ La collection<span style="text-decoration: none"><span style="font-style: normal
 						['uid' => 139735,
 						 'starttime' => 0,
 						 'endtime' => 0,
-						 'hidden' => 0,
+						 'deleted' => 0,'hidden' => 0,
 						 'crdate' => 1357592258,
 						 'cruser_id' => 22,
 						 'short' => null,
@@ -405,7 +443,26 @@ La collection<span style="text-decoration: none"><span style="font-style: normal
 
 		];
 	}
+	public function findAllContentsSince($update_date) {
+			$contents=$this->findAllContents();
+			$contents[0]['bodytext']='Modification de contenu';
+			$contents[0]['header']='A haute voix... modif';
 
+			$contents[]=[
+							 'uid' => 188,
+						 'crdate' => 1298390490,
+						 'starttime' => 1298389541,
+						 'endtime' => 0,
+						 'hidden' => 0,
+						 'cruser_id' => 1,
+						 'image' => '',
+						 'title' => '',
+							 'bodytext' => "<ul><li>Internet est consultable dans tous les pôles thématiques du réseau : <link typo3/fileadmin/fichiers/fichiers_joints/reglement_interieur/REGLEMENT-INTERIEUR-2013-annexe3.pdf _blank download>voir la charte d'utilisation.<br /><br /></link></li></ul>",
+							 'header'=> "Internet & Wi-Fi"
+			];
+			return $contents;
+
+	}
 	public function findAllContents($page_id=false) {
 		return [
 						[
diff --git a/tests/library/Class/Import/Typo3Test.php b/tests/library/Class/Import/Typo3Test.php
index f0b14d6f1eb360abdf1a594c7455366db3864315..5eb12398020729f53a9b9597921ab434ec368feb 100644
--- a/tests/library/Class/Import/Typo3Test.php
+++ b/tests/library/Class/Import/Typo3Test.php
@@ -30,28 +30,24 @@ abstract class Import_Typo3TestCase extends ModelTestCase {
 	public function setUp() {
 		parent::setUp();
 		Class_Import_Typo3_Logs::getInstance()->cleans();
-    Class_Article::beVolatile();
-    Class_Users::beVolatile();
-    Class_ArticleCategorie::beVolatile();
-    Class_Catalogue::beVolatile();
-    Class_CodifThesaurus::beVolatile();
-    Class_Sitotheque::beVolatile();
-    Class_SitothequeCategorie::beVolatile();
-
+		Storm_Model_Loader::defaultToVolatile();
 		Class_CustomField_Model::registerAll([
-																					new Class_CustomField_ModelConfiguration_Article()
+																					new Class_CustomField_ModelConfiguration_Article(),
+ 																					new Class_CustomField_ModelConfiguration_Sitotheque(),
+ 																					new Class_CustomField_ModelConfiguration_SitothequeCategorie(),
+ 																					new Class_CustomField_ModelConfiguration_Catalogue(),
+																					new Class_CustomField_ModelConfiguration_ArticleCategorie()
 
 																					])
 			;
-		Class_CustomField_Meta::beVolatile();
-		Class_CustomField::beVolatile();
-		Class_CustomField_Value::beVolatile();
+
 		$this->mock_sql = Storm_Test_ObjectWrapper::mock();
 		$this->old_sql = Zend_Registry::get('sql');
 		Zend_Registry::set('sql', $this->mock_sql);
 
 		$this->mock_sql->whenCalled('execute')
 									 ->answers(true);
+
 		$this->fixture('Class_CustomField_Meta',
 									 ['id' => 1,
 										'label' => 'uid_typo3',
@@ -67,21 +63,14 @@ abstract class Import_Typo3TestCase extends ModelTestCase {
 
 		$this->migration = new Class_Import_Typo3();
 		$this->migration->setTypo3DB(new MockTypo3DB());
-/*		$this->fixture('Class_CustomField_Value',
-			['id' => 25,
-			'custom_field_id' => 1,
-			'model_id' => 1,
-			'value' => 'enabled']);
-
-*/
 	}
 
 
 	public function tearDown() {
 		Zend_Registry::set('sql', $this->old_sql);
+		Storm_Model_Loader::defaultToDb();
 		parent::tearDown();
 	}
-
 }
 
 
@@ -89,25 +78,63 @@ abstract class Import_Typo3TestCase extends ModelTestCase {
 class Import_Typo3UsersTest extends Import_Typo3TestCase {
 	public function setUp() {
 		parent::setUp();
-		$this->migration->run('users');
+		$this->fixture('Class_Users',
+									 ['id' => 12,
+										'login' => 'toto',
+										'password' => 'XXzsinaded',
+										'nom' => 'Un nom']);
+
+		$this->onLoaderOfModel('Class_Users')
+				 ->whenCalled('deleteBy')
+				 ->with(['where' => 'ROLE_LEVEL < 6 AND ROLE_LEVEL <> 2'])
+				 ->answers(null);
+
+		$this->report = $this->migration->run('users');
+	}
+
+
+	/** @test */
+	public function shouldHave3Users() {
+		$this->assertEquals(3, Class_Users::count(), $this->report);
 	}
 
 
 	/** @test */
-	public function userShouldBeInsertedInDB() {
-		$this->assertEquals('toto', Class_Users::findFirstBy(['login' => 'toto'])->getLogin());
+	public function totoShouldBeImported() {
+		$this->_userShouldBeImported(Class_Users::findFirstBy(['login' => 'toto']),
+																 ZendAfi_Acl_AdminControllerRoles::ADMIN_PORTAIL,
+																 'toto@null.com', 'toto');
 	}
 
 
 	/** @test */
-	public function totoShouldBeAdmin() {
-		$this->assertTrue(Class_Users::findFirstBy(['login' => 'toto'])->isAdmin());
+	public function totoShouldHaveBeenUpdated() {
+		$this->assertEquals(12, Class_Users::findFirstBy(['login' => 'toto'])->getId());
 	}
 
 
 	/** @test */
-	public function jeanShouldBeModoPortail() {
-		$this->assertEquals(ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL, Class_Users::findFirstBy(['login' => 'jean'])->getRoleLevel());
+	public function jeanShouldBeImported() {
+		$this->_userShouldBeImported(Class_Users::findFirstBy(['login' => 'jean']),
+																 ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL,
+																 'jean-jeantoto@null.com', 'Jean Jean');
+	}
+
+
+	/** @test */
+	public function sergeShouldBeImported() {
+		$this->_userShouldBeImported(Class_Users::findFirstBy(['login' => 'sserge']),
+																 ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL,
+																 'serge@null.com', 'Serge Serge');
+	}
+
+
+	protected function _userShouldBeImported($user, $role, $mail, $name) {
+		$this->assertNotNull($user);
+		$this->assertEquals($role, $user->getRoleLevel());
+		$this->assertEquals('achanger', $user->getPassword());
+		$this->assertEquals($mail, $user->getMail());
+		$this->assertEquals($name, $user->getNom());
 	}
 }
 
@@ -133,6 +160,16 @@ class Import_Typo3CategoryTest extends Import_Typo3TestCase {
 		$this->assertNotNull($parent);
 	}
 
+	/** @test */
+	public function sitoCategorieShouldHaveUidTypo3() {
+		$this->assertEquals('80',Class_SitothequeCategorie::findFirstBy(['libelle' => 'Musique & Cinéma'])->getCustomField('uid_typo3'));
+	}
+
+	/** @test */
+	public function categoryShouldHaveUidTypo3() {
+		$this->assertEquals(99,Class_ArticleCategorie::findFirstBy(['libelle' => 'Musique & Cinéma'])->getParent()->getCustomField('uid_typo3'));
+
+	}
 
 	/** @test */
 	public function categoryMusiqueCinemaShouldBeChildOfArt() {
@@ -552,14 +589,152 @@ class Import_Typo3SitothequeTest extends Import_Typo3TestCase {
 												$this->sito->getCategorie()->getPath());
 	}
 
-/** @test */
+  /** @test */
 	public function ouestCanadienShouldContainsUrlBokehSearch() {
 		$this->assertEquals('/miop-test.net/recherche/viewnotice/clef/OUEST_CANADIEN', Class_Sitotheque::findFirstBy(['titre' => 'L\'ouest canadien'])->getUrl());
 
 	}
 
+
+  /** @test */
+	public function ouestCanadienShouldStoreUidTypo3() {
+		$this->assertEquals(14479, Class_Sitotheque::findFirstBy(['titre' => 'L\'ouest canadien'])->getCustomField('uid_typo3'));
+
+	}
+
 }
 
+class Import_Typo3UpdateArticleTest extends Import_Typo3TestCase {
+	protected $article_voix;
+	public function setUp() {
+		parent::setUp();
+		$this->migration->import_categories();
+		$this->migration->importArticles();
+
+		$this->migration->importArticlesPages();
+		Class_Article::setTimeSource(new TimeSourceForTest('2015-02-03 10:00:00'));
+
+		$this->article_voix=Class_Article::findFirstBy(['titre' => 'A haute voix... le roman se fait entendre...']);
+		$this->migration->updateCategories(888);
+
+		Class_CustomField_Value::clearCache();
+		Class_ArticleCategorie::clearCache();
+
+
+		$this->migration->updateArticlePages(888);
+		$this->migration->updateArticles(888);
+	}
+
+	public function expectedUpdateArticle() {
+		$articles=MockTypo3DB::findAllArticles();
+		return [
+						[
+						 'title' => 'Tous à bord du bateau pirate',
+							['titre' =>'Tous à bord du bateau pirate',
+							 'description' => '<img src="http://www.mediathequeouestprovence.fr/uploads/pics/bateau.jpg" alt=""/><p>'.$articles[0]['short'].'</p>',
+							 'debut' => '2014-11-04 15:23',
+							 'fin' => '2015-02-03 15:23',
+							 'avis' => false,
+							 'tags' => 'pirate;bateau',
+							 'events_debut' => null,
+							 'events_fin' => null,
+							 'indexation' => 1,
+							 'cacher_titre' => 0,
+							 'date_maj' => '2015-02-03 10:00:00',
+							 'date_creation' => '1974-06-24 04:44:21',
+							 'status' => 3,
+							 'id_lieu' => 0,
+							 'domaine_ids' => '5;7;6',
+							 'id_origine' => 0,
+							 'all_day' => false,
+							 'langue' => 'fr',
+							 'id' => 1,
+							 'id_user' => 0,
+							 'id_article' => 1
+							]],
+
+						['title' => 'A bord du bateau pirate',
+							[]], //updated
+
+						['title' => 'Wiki Bokeh',
+						 ['contenu' => '<p>MODIFIEDWelcome to <a href="http://wiki.bokeh-library-portal.org">Wiki Bokeh</a></p>']], //updated
+
+						['title' => 'Architecture', //deleted
+						 []],
+
+						['title' => 'Internet & Wi-Fi',
+						 ['contenu' => "<ul><li>Internet est consultable dans tous les pôles thématiques du réseau : <a href=\"typo3/fileadmin/fichiers/fichiers_joints/reglement_interieur/REGLEMENT-INTERIEUR-2013-annexe3.pdf\">voir la charte d'utilisation.<br /><br /></a></li></ul>"]],
+						['title' => 'A haute voix... le roman se fait entendre...',
+						 [
+						 ]],
+						['title' => 'A haute voix... modif',
+						 ['contenu' =>'<p>Modification de contenu</p>',
+						 ]],
+						['title' => 'Crash Test',
+						 ['description' => '<p>Crash</p>'
+						 ]]
+
+
+
+		];
+	}
+
+	/**
+	 * @dataProvider expectedUpdateArticle
+	 * @test
+	 */
+	public function updateArticleShouldBeUpdated($title,$article) {
+		$article_class_found=Class_Article::findFirstBy(['titre' => $title]);
+		if (empty($article))
+			return $this->assertNull($article_class_found);
+
+		$article_found=$article_class_found->attributesToArray();
+		foreach ($article  as $key => $value) {
+			$this->assertEquals($value,$article_found[$key]);
+		}
+
+	}
+
+	/** @test */
+	public function categoryForBateauPirateShouldBeJeux() {
+		$article=Class_Article::findFirstBy(['titre' => 'Tous à bord du bateau pirate']);
+		$this->assertEquals(Class_ArticleCategorie::findFirstBy(['libelle' => 'Jeux'])->getId(),$article->getCategorie()->getId());
+	}
+
+  /** @test */
+	public function parentCategoryForJeuxShouldBeArt() {
+		Class_ArticleCategorie::clearCache();
+		$this->assertEquals("Art",Class_ArticleCategorie::findFirstBy(['libelle' => 'Jeux'])->getParent()->getLibelle());
+	}
+
+  /** @test */
+	public function categoryDiversShouldBeRenamedDhiver() {
+		$this->assertEquals("d'hiver",Class_ArticleCategorie::findFirstByCustomFieldValue(Class_Import_Typo3::UID_TYPO3_CF,81)->getLibelle());
+
+	}
+
+	/** @test */
+	public function articleShouldBeModified() {
+		$this->assertEquals(14474, Class_Article::findFirstBy(['titre' => 'Tous à bord du bateau pirate'])->getCustomField('uid_typo3'));
+	}
+
+	/** @test */
+	public function AhauteVoixShouldKeepSameArticleId() {
+		$article=Class_Article::findFirstBy(['titre' => 'A haute voix... modif']);
+		$this->assertEquals(13973,$article->getCustomField('uid_typo3'));
+		$this->assertEquals($article->getId(), $this->article_voix->getId());
+	}
+
+	/** @test */
+	public function articleReallyYouCrashShouldNotBeModified() {
+		$this->assertEquals(84888,Class_Article::findFirstBy(['titre' => 'Realy ? you crash ?'])->getCustomField('uid_typo3'));
+		$this->assertEquals(666,Class_Article::findFirstBy(['titre' => 'Crash Test'])->getCustomField('uid_typo3'));
+	}
+
+
+
+
+}
 
 
 class Import_Typo3CustomFieldTest extends Import_Typo3TestCase {
@@ -582,14 +757,6 @@ class Import_Typo3CustomFieldTest extends Import_Typo3TestCase {
 		$this->assertEquals(13973,$this->custom_field_values[0]->getValue());
 	}
 
-  /** @test */
-	public function testShouldtypo3() {
-		$article=Class_Article::findFirstBy(['titre' => 'A haute voix... le roman se fait entendre...']);
-		$article->setUidTypo3('345');
-		$article->save();
-		$this->assertFalse(isset($article->attributesToArray()['uid_typo3']));
-	}
-
 
   /** @test */
 	public function customfieldShouldbeUnique() {