diff --git a/FEATURES/126465 b/FEATURES/126465
new file mode 100644
index 0000000000000000000000000000000000000000..26151d978b38faddf1b18f5214d5d8a29e595b1b
--- /dev/null
+++ b/FEATURES/126465
@@ -0,0 +1,10 @@
+        '126465' =>
+            ['Label' => $this->_('Facettes dynamiques : Permettre d\'enregistrer des règles de paramétrages multiples'),
+             'Desc' => $this->_('Avoir plusieurs règles de paramétrages possibles, permettant de fusionner plusieurs champs unimarc pour une seule facette'),
+             'Image' => '',
+             'Video' => '',
+             'Category' => '',
+             'Right' => function($feature_description, $user) {return true;},
+             'Wiki' => 'http://wiki.bokeh-library-portal.org/index.php?title=Facettes_dynamiques',
+             'Test' => '',
+             'Date' => '2021-03-09'],
\ No newline at end of file
diff --git a/VERSIONS_WIP/126465 b/VERSIONS_WIP/126465
new file mode 100644
index 0000000000000000000000000000000000000000..feb579f303533b620ab03e65c8cdab55a6194a52
--- /dev/null
+++ b/VERSIONS_WIP/126465
@@ -0,0 +1 @@
+ - ticket #126465 : Facettes dynamiques : Permettre d'enregistrer des règles de paramétrages multiples
\ No newline at end of file
diff --git a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/DataProfileControllerTest.php b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/DataProfileControllerTest.php
index c6d6b5ef8492633fe7b83953b9c72caeb886c7a5..dc2a8ef543900a8ddebac2a4097b7d48cadda213 100644
--- a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/DataProfileControllerTest.php
+++ b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/DataProfileControllerTest.php
@@ -1327,9 +1327,9 @@ abstract class Cosmo_DataProfileControllerAuthorityTestCase
     $this->fixture('Class_CodifThesaurus',
                    ['id' => 5,
                     'libelle' => 'Mots-clés TESS',
-                    'rule_zone' => '609',
-                    'rule_label_field' => 'a',
-                    'rule_id_field' => '9',
+                    'rule_list_zone' => ['609'],
+                    'rule_list_label_field' => ['a'],
+                    'rule_list_id_field' => ['9'],
                     'id_thesaurus' => 'MOTS']);
   }
 }
diff --git a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/DynamicFacetsControllerTest.php b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/DynamicFacetsControllerTest.php
index ca4047fa16ffed6dace6e55cd326c49c6f9f549c..8889d783913ba013d31f0e2fa31bcb1d6f740062 100644
--- a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/DynamicFacetsControllerTest.php
+++ b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/DynamicFacetsControllerTest.php
@@ -31,18 +31,17 @@ class Cosmo_DynamicFacetsControllerIndexTest extends CosmoControllerTestCase {
                     'id_thesaurus' => 'DOCU',
                     'id_origine' => null,
                     'code' => 'DOCU',
-                    'rule_zone' => '345',
-                    'rule_label_field' => 't',
-                    'rule_id_field' => '9']);
+                    'rule_list_zone' => ['345'],
+                    'rule_list_label_field' => ['t'],
+                    'rule_list_id_field' => ['9']]);
 
-    $this->dispatch('/cosmo/facets/index', true);
+    $this->dispatch('/cosmo/facets/index');
   }
 
 
   /** @test */
   public function titleShouldBeDynamicFacets() {
     $this->assertXpathContentContains('//h1' , 'Facettes dynamiques');
-
   }
 
 
@@ -76,7 +75,7 @@ class Cosmo_DynamicFacetsControllerIndexTest extends CosmoControllerTestCase {
 class Cosmo_DynamicFacetsControllerAddTest extends CosmoControllerTestCase {
   public function setUp() {
     parent::setUp();
-    $this->dispatch('/cosmo/facets/add', true);
+    $this->dispatch('/cosmo/facets/add');
   }
 
 
@@ -94,31 +93,31 @@ class Cosmo_DynamicFacetsControllerAddTest extends CosmoControllerTestCase {
 
   /** @test */
   public function zoneShouldBePresent() {
-    $this->assertXPath('//input[@name="rule_zone"]');
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"name":"rule_list_zone"');
   }
 
 
   /** @test */
   public function labelFieldShouldBePresent() {
-    $this->assertXPath('//select[@name="rule_label_field"]');
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"name":"rule_list_label_field"');
   }
 
 
   /** @test */
   public function idFieldShouldBePresent() {
-    $this->assertXPath('//select[@name="rule_id_field"]');
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"name":"rule_list_id_field"');
   }
 
 
   /** @test */
   public function pageShouldContainsSelectForFilterField() {
-    $this->assertXPath('//select[@name="rule_filter_field"]');
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"name":"rule_list_filter_field"');
   }
 
 
   /** @test */
   public function pageShouldContainsInputForFilterValue() {
-    $this->assertXPath('//input[@name="rule_filter_value"]');
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"name":"rule_list_filter_value"');
   }
 
 
@@ -130,18 +129,19 @@ class Cosmo_DynamicFacetsControllerAddTest extends CosmoControllerTestCase {
 
   /** @test */
   public function inputLabelStartPosShouldBeNumberWithValueOne() {
-    $this->assertXPath('//input[@name="rule_label_start_pos"][@type="number"][@min="1"][@value="1"]');
+    $this->assertXpathContentRegex('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '/("name":"rule_list_label_start_pos")[^{}]*("type":"number")[^{}]*("default_value":1)/');
   }
 
 
   /** @test */
   public function inputLabelLengthShouldBeNumberWithValueZero() {
-    $this->assertXPath('//input[@name="rule_label_length"][@type="number"][@min="0"][@value="0"]');
+    $this->assertXpathContentRegex('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]',  '/("name":"rule_list_label_length")[^{}]*("type":"number")[^{}]*("default_value":0)/');
   }
 }
 
 
 
+
 class Cosmo_DynamicFacetsControllerAddPostValidTest extends CosmoControllerTestCase {
   protected $model;
 
@@ -149,13 +149,13 @@ class Cosmo_DynamicFacetsControllerAddPostValidTest extends CosmoControllerTestC
     parent::setUp();
 
     $this->postDispatch('/cosmo/facets/add', ['libelle'          => 'New facet name',
-                                              'rule_zone'        => '609',
-                                              'rule_label_field' => 'a',
-                                              'rule_id_field'    => '9',
-                                              'rule_label_start_pos' => '2',
-                                              'rule_label_length' => '4',
-                                              'rule_filter_field' => 't',
-                                              'rule_filter_value' => 'Take me']);
+                                              'rule_list_zone'        => ['609'],
+                                              'rule_list_label_field' => ['a'],
+                                              'rule_list_id_field'    => ['9'],
+                                              'rule_list_label_start_pos' => ['2'],
+                                              'rule_list_label_length' => ['4'],
+                                              'rule_list_filter_field' => ['t'],
+                                              'rule_list_filter_value' => ['Take me']]);
 
     Class_CodifThesaurus::clearCache();
     $this->model = Class_CodifThesaurus::findFirstBy(['libelle' => 'New facet name']);
@@ -176,43 +176,43 @@ class Cosmo_DynamicFacetsControllerAddPostValidTest extends CosmoControllerTestC
 
   /** @test */
   public function zoneShouldBe609() {
-    $this->assertEquals('609', $this->model->getRuleZone());
+    $this->assertSame(['609'], $this->model->getRuleListZone());
   }
 
 
   /** @test */
   public function labelFieldShouldBeA() {
-    $this->assertEquals('a', $this->model->getRuleLabelField());
+    $this->assertSame(['a'], $this->model->getRuleListLabelField());
   }
 
 
   /** @test */
   public function idFieldShouldBe9() {
-    $this->assertEquals('9', $this->model->getRuleIdField());
+    $this->assertSame(['9'], $this->model->getRuleListIdField());
   }
 
 
   /** @test */
   public function rulesLabelStartPosShouldBeTwo() {
-    $this->assertEquals('2', $this->model->getRulesAsArray()['rule_label_start_pos']);
+    $this->assertSame(['2'], $this->model->getRulesAsArray()['rule_list_label_start_pos']);
   }
 
 
   /** @test */
   public function rulesLabelLengthShouldBeFour() {
-    $this->assertEquals('4', $this->model->getRulesAsArray()['rule_label_length']);
+    $this->assertSame(['4'], $this->model->getRulesAsArray()['rule_list_label_length']);
   }
 
 
   /** @test */
   public function ruleFilterFieldShouldBeT() {
-    $this->assertEquals('t', $this->model->getRulesAsArray()['rule_filter_field']);
+    $this->assertSame(['t'], $this->model->getRulesAsArray()['rule_list_filter_field']);
   }
 
 
   /** @test */
   public function ruleFilterValueShouldBeTakeMe() {
-    $this->assertEquals('Take me', $this->model->getRulesAsArray()['rule_filter_value']);
+    $this->assertSame(['Take me'], $this->model->getRulesAsArray()['rule_list_filter_value']);
   }
 }
 
@@ -223,10 +223,14 @@ class Cosmo_DynamicFacetsControllerValidateTest extends CosmoControllerTestCase
   /** @test */
   public function idThesaurusShouldBeDOC0() {
     $this->postDispatch('/cosmo/facets/add', ['libelle' => 'doc',
-                                              'rule_zone' => '033',
-                                              'rule_label_field' => '8',
-                                              'rule_label_start_pos' => '1',
-                                              'rule_label_length' => '0']);
+                                              'rule_list_zone' => ['033'],
+                                              'rule_list_label_field' => ['8'],
+                                              'rule_list_label_start_pos' => ['1'],
+                                              'rule_list_label_length' => ['0'],
+                                              'rule_list_id_field' => [''],
+                                              'rule_list_filter_field' => [''],
+                                              'rule_list_filter_value' => ['']]);
+
     $this->assertEquals('DOC0',
                         Class_CodifThesaurus::findFirstBy(['libelle'=>'doc'])->getIdThesaurus());
   }
@@ -237,16 +241,19 @@ class Cosmo_DynamicFacetsControllerValidateTest extends CosmoControllerTestCase
     $this->fixture('Class_CodifThesaurus',
                    ['libelle' => 'doc that i love',
                     'id_thesaurus' => 'DOC0',
-                    'rule_zone' => '345',
-                    'rule_label_field' => 't',
-                    'rule_label_start_pos' => '1',
-                    'rule_label_length' => '0']);
+                    'rule_list_zone' => ['345'],
+                    'rule_list_label_field' => ['t'],
+                    'rule_list_label_start_pos' => ['1'],
+                    'rule_list_label_length' => ['0']]);
 
     $this->postDispatch('/cosmo/facets/add', ['libelle' => 'doc',
-                                              'rule_zone' => '345',
-                                              'rule_label_field' => '3',
-                                              'rule_label_start_pos' => '1',
-                                              'rule_label_length' => '0']);
+                                              'rule_list_zone' => ['345'],
+                                              'rule_list_label_field' => ['3'],
+                                              'rule_list_label_start_pos' => ['1'],
+                                              'rule_list_label_length' => ['0'],
+                                              'rule_list_id_field' => [''],
+                                              'rule_list_filter_field' => [''],
+                                              'rule_list_filter_value' => ['']]);
 
     $this->assertEquals('DOC1',
                         Class_CodifThesaurus::findFirstBy(['libelle'=>'doc'])->getIdThesaurus());
@@ -259,16 +266,19 @@ class Cosmo_DynamicFacetsControllerValidateTest extends CosmoControllerTestCase
     $this->fixture('Class_CodifThesaurus',
                    ['libelle' => 'doc that i love',
                     'id_thesaurus' => 'DOCU',
-                    'rule_zone' => '345',
-                    'rule_label_field' => 't',
-                    'rule_label_start_pos' => '1',
-                    'rule_label_length' => '0']);
+                    'rule_list_zone' => ['345'],
+                    'rule_list_label_field' => ['t'],
+                    'rule_list_label_start_pos' => ['1'],
+                    'rule_list_label_length' => ['0']]);
 
     $this->postDispatch('/cosmo/facets/add', ['libelle' => 'docu',
-                                              'rule_zone' => '345',
-                                              'rule_label_field' => '3',
-                                              'rule_label_start_pos' => '1',
-                                              'rule_label_length' => '0']);
+                                              'rule_list_zone' => ['345'],
+                                              'rule_list_label_field' => ['3'],
+                                              'rule_list_label_start_pos' => ['1'],
+                                              'rule_list_label_length' => ['0'],
+                                              'rule_list_id_field' => [''],
+                                              'rule_list_filter_field' => [''],
+                                              'rule_list_filter_value' => ['']]);
 
     $this->assertEquals('DOC0',
                         Class_CodifThesaurus::findFirstBy(['libelle'=>'docu'])->getIdThesaurus());
@@ -279,10 +289,13 @@ class Cosmo_DynamicFacetsControllerValidateTest extends CosmoControllerTestCase
   /** @test */
   public function withSpecialCharsNewIdThesaurusShouldBeFourLetters() {
     $this->postDispatch('/cosmo/facets/add', ['libelle' => 'Année top 5',
-                                              'rule_zone' => '066',
-                                              'rule_label_field' => '6',
-                                              'rule_label_start_pos' => '1',
-                                              'rule_label_length' => '0']);
+                                              'rule_list_zone' => ['066'],
+                                              'rule_list_label_field' => ['6'],
+                                              'rule_list_label_start_pos' => ['1'],
+                                              'rule_list_label_length' => ['0'],
+                                              'rule_list_id_field' => [''],
+                                              'rule_list_filter_field' => [''],
+                                              'rule_list_filter_value' => ['']]);
 
     $this->assertEquals('ANNE',
                         Class_CodifThesaurus::findFirstBy(['libelle'=>'Année top 5'])->getIdThesaurus());
@@ -302,11 +315,11 @@ class Cosmo_DynamicFacetsControllerEditTest extends CosmoControllerTestCase {
                     'id_thesaurus' => 'DOCU',
                     'id_origine' => null,
                     'code' => 'DOCU',
-                    'rule_zone' => '345',
-                    'rule_label_field' => 't',
-                    'rule_id_field' => '9']);
+                    'rule_list_zone' => ['345'],
+                    'rule_list_label_field' => ['t'],
+                    'rule_list_id_field' => ['9']]);
 
-    $this->dispatch('/cosmo/facets/edit/id/3', true);
+    $this->dispatch('/cosmo/facets/edit/id/3');
   }
 
 
@@ -324,19 +337,19 @@ class Cosmo_DynamicFacetsControllerEditTest extends CosmoControllerTestCase {
 
   /** @test */
   public function zoneShouldBe345() {
-    $this->assertXPath('//input[@name="rule_zone"][@value="345"]');
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"rule_list_zone":["345"]');
   }
 
 
   /** @test */
   public function labelFieldShouldBeT() {
-    $this->assertXPath('//select[@name="rule_label_field"]//option[@value="t"][@selected]');
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"rule_list_label_field":["t"]');
   }
 
 
   /** @test */
   public function idFieldShouldBe9() {
-    $this->assertXPath('//select[@name="rule_id_field"]//option[@value="9"][@selected]');
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"rule_list_id_field":["9"]');
   }
 
 
@@ -360,20 +373,22 @@ class Cosmo_DynamicFacetsControllerEditPostTest extends CosmoControllerTestCase
                     'id_thesaurus' => 'DOCU',
                     'id_origine' => null,
                     'code' => 'DOCU',
-                    'rule_zone' => '345',
-                    'rule_label_field' => 't',
-                    'rule_id_field' => '9',
-                    'rule_label_start_pos' => '1',
-                    'rule_label_length' => '0']);
+                    'rule_list_zone' => ['345'],
+                    'rule_list_label_field' => ['t'],
+                    'rule_list_id_field' =>  ['9'],
+                    'rule_list_label_start_pos' => ['1'],
+                    'rule_list_label_length' => ['0']]);
 
     $this->postDispatch('/cosmo/facets/edit/id/3',
                         ['libelle' => 'Document',
                          'libelle_facette' => 'Document',
-                         'rule_zone' => '609',
-                         'rule_label_field' => 'a',
-                         'rule_id_field' => '3',
-                         'rule_label_start_pos' => '1',
-                         'rule_label_length' => '0']);
+                         'rule_list_zone' => ['609'],
+                         'rule_list_label_field' => ['a'],
+                         'rule_list_id_field' => ['3'],
+                         'rule_list_label_start_pos' => ['1'],
+                         'rule_list_label_length' => ['0'],
+                         'rule_list_filter_field' => [''],
+                         'rule_list_filter_value' => ['']]);
   }
 
 
@@ -391,6 +406,170 @@ class Cosmo_DynamicFacetsControllerEditPostTest extends CosmoControllerTestCase
 
   /** @test */
   public function ruleZoneShouldBecome609() {
-    $this->assertEquals('609', Class_CodifThesaurus::find(3)->getRuleZone());
+    $this->assertSame(['609'], Class_CodifThesaurus::find(3)->getRuleListZone());
+  }
+}
+
+
+
+
+class Cosmo_DynamicFacetsControllerEditWithManyRulesTest extends CosmoControllerTestCase {
+
+  public function setUp() {
+    parent::setUp();
+
+    Class_CodifThesaurus::newFromRow(['id' => 103,
+                                      'libelle' => 'Document',
+                                      'libelle_facette' => 'Document',
+                                      'id_thesaurus' => 'DOCU',
+                                      'id_origine' => null,
+                                      'code' => 'DOCU',
+                                      'rules' => '[{"Zone":"345","LabelField":"t"},{"Zone":"355","LabelField":"t"}]']);
+
+    $this->dispatch('/cosmo/facets/edit/id/103');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsMultiInputRuleZone_345_355() {
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"rule_list_zone":["345","355"]');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsMultiInputRuleLabelField_t_t() {
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"rule_list_label_field":["t","t"]');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsMultiInputRuleWithDefaultLabelStartPos_1_1() {
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"rule_list_label_start_pos":[1,1]');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsMultiInputRuleWithDefaultLabelLength_0_0() {
+    $this->assertXpathContentContains('//script[contains(text(), \'$("#multi_inputs_multi_rules").multi_inputs\')]', '"rule_list_label_length":[0,0]');
+  }
+}
+
+
+
+
+class Cosmo_DynamicFacetsControllerPostWithManyRulesTest extends CosmoControllerTestCase {
+
+  protected
+    $_facet_multi,
+    $_fields_values = [
+                       'rule_list_zone' => ['345', '355', '365'],
+                       'rule_list_label_field' => ['a', 'b', 'c'],
+                       'rule_list_id_field' => ['9', '8', '7'],
+                       'rule_list_label_start_pos' => ['2', '3', '4'],
+                       'rule_list_label_length' => ['4', '5', '6'],
+                       'rule_list_filter_field' => ['t', 'u', 'v'],
+                       'rule_list_filter_value' => ['MultInput', 'multi', 'input']
+    ];
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->postDispatch('/cosmo/facets/add',
+                        array_merge(['libelle' => 'Facets multi rules'], $this->_fields_values));
+
+    Class_CodifThesaurus::clearCache();
+    $this->_facet_multi = Class_CodifThesaurus::findFirstBy(['libelle' => 'Facets multi rules']);
+  }
+
+
+  public function datasRuleList() {
+    $datas = [];
+    foreach ($this->_fields_values as $field => $values)
+      $datas [] = [$field, $values];
+
+    return $datas;
+  }
+
+
+  /**
+   * @test
+   * @dataProvider datasRuleList
+   */
+  public function datasFromRuleListShouldBeTableTypeWithValues($field, $value) {
+    $this->assertSame($value, $this->_facet_multi->callGetterByAttributeName($field));
+  }
+}
+
+
+
+
+class Cosmo_DynamicFacetsControllerEditPostAddRulesEmptyTest extends CosmoControllerTestCase {
+
+  protected $_facet_multi;
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->postDispatch('/cosmo/facets/add',
+                        ['libelle' => 'Facette avec 3 regles',
+                         'libelle_facette' => 'Document',
+                         'rule_list_zone' => ['345', '355', ''],
+                         'rule_list_label_field' => ['t', 'u', ''],
+                         'rule_list_id_field' => ['9', '', ''],
+                         'rule_list_label_start_pos' => ['1', '1', '1'],
+                         'rule_list_label_length' => ['0', '0', '0'],
+                         'rule_list_filter_field' => ['', '', ''],
+                         'rule_list_filter_value' => ['', '', '']]);
+
+    Class_CodifThesaurus::clearCache();
+    $this->_facet_multi = Class_CodifThesaurus::findFirstBy(['libelle' => 'Facette avec 3 regles']);
+  }
+
+
+  /** @test */
+  public function rulesListZoneShouldBeSavedWithoutZoneEmpty() {
+    $this->assertSame(['345', '355'], $this->_facet_multi->getRuleListZone());
   }
-}
\ No newline at end of file
+}
+
+
+
+
+class Cosmo_DynamicFacetsControllerEditPostDeleteRulesTest extends CosmoControllerTestCase {
+
+  protected $_facet_multi;
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture(Class_CodifThesaurus::class,
+                   ['id' => 303,
+                    'libelle' => 'Document',
+                    'libelle_facette' => 'Document',
+                    'id_thesaurus' => 'DOCU',
+                    'id_origine' => null,
+                    'code' => 'DOCU',
+                    'rule_list_zone' => ['345', '350', '355'],
+                    'rule_list_label_field' => ['t', 'y', 'u'],
+                    'rule_list_id_field' => ['9', '8', ''],
+                    'rule_list_label_start_pos' => ['1', '2', '1'],
+                    'rule_list_label_length' => ['0', '0', '0'],
+                    'rule_list_filter_field' => ['', '', ''],
+                    'rule_list_filter_value' => ['', '', '']]);
+
+    $this->postDispatch('/cosmo/facets/edit/id/303',
+                        ['rule_list_zone' => ['345', '355'],
+                         'rule_list_label_field' => ['t', 'u'],
+                         'rule_list_id_field' => ['9', ''],
+                         'rule_list_label_start_pos' => ['1', '1'],
+                         'rule_list_label_length' => ['0', '0'],
+                         'rule_list_filter_field' => ['', ''],
+                         'rule_list_filter_value' => ['', '']]);
+  }
+
+
+  /** @test */
+  public function thesaurusZone350ShouldBeDeleted() {
+    $this->assertSame(['345', '355'], Class_CodifThesaurus::find(303)->getRuleListZone());
+  }
+}
diff --git a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php
index a7b656e0a3f67c74901eb8fdc0ccda595e993a25..d8c9f09a8666947304a71f92d5ddbbd0dd54ea25 100644
--- a/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php
+++ b/cosmogramme/cosmozend/tests/application/modules/cosmo/controllers/IntegrationControllerTest.php
@@ -898,8 +898,8 @@ class Cosmo_IntegrationControllerClearActionPostTest extends CosmoControllerTest
                     'id_thesaurus' => 'DOCU',
                     'id_origine' => null,
                     'code' => 'DOCU',
-                    'rule_zone' => '099',
-                    'rule_label_field' => 't']);
+                    'rule_list_zone' => ['099'],
+                    'rule_list_label_field' => ['t']]);
 
     $this->_mock_sql = $this->mock()->whenCalled('execute')->answers(null);
 
diff --git a/cosmogramme/sql/patch/patch_406.php b/cosmogramme/sql/patch/patch_406.php
new file mode 100644
index 0000000000000000000000000000000000000000..a9cd8bd2d92a891b4cd70e5c1f6e8e7374e3d874
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_406.php
@@ -0,0 +1,7 @@
+<?php
+$adapter = Zend_Db_Table::getDefaultAdapter();
+
+try {
+  $adapter->query("alter table `codif_thesaurus` modify `rules` text");
+} catch(Exception $e) {
+}
\ No newline at end of file
diff --git a/cosmogramme/tests/php/classes/KohaRecordIntegrationTest.php b/cosmogramme/tests/php/classes/KohaRecordIntegrationTest.php
index 171fcb29a5cc0a205e29c67aed00fc07aba6af9c..bde8d1cd677a0e2d39bf002cddcf3738d1938ddb 100644
--- a/cosmogramme/tests/php/classes/KohaRecordIntegrationTest.php
+++ b/cosmogramme/tests/php/classes/KohaRecordIntegrationTest.php
@@ -159,10 +159,10 @@ class KohaRecordIntegrationFacetPresseTest extends KohaRecordIntegrationTestCase
                     'id_thesaurus' => 'ANNE',
                     'id_origine' => null,
                     'code' => 'annee',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 'w',
-                    'rule_label_start_pos' => 1,
-                    'rule_label_length' => 4
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['w'],
+                    'rule_list_label_start_pos' => [1],
+                    'rule_list_label_length' => [4]
                    ]);
 
 
@@ -172,10 +172,10 @@ class KohaRecordIntegrationFacetPresseTest extends KohaRecordIntegrationTestCase
                     'id_thesaurus' => 'MOIS',
                     'id_origine' => null,
                     'code' => 'mois',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 'w',
-                    'rule_label_start_pos' => 6,
-                    'rule_label_length' => 2
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['w'],
+                    'rule_list_label_start_pos' => [6],
+                    'rule_list_label_length' => [2]
                    ]);
 
     $this->fixture('Class_CodifThesaurus',
@@ -184,10 +184,10 @@ class KohaRecordIntegrationFacetPresseTest extends KohaRecordIntegrationTestCase
                     'id_thesaurus' => 'JOUR',
                     'id_origine' => null,
                     'code' => 'jour',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 'w',
-                    'rule_label_start_pos' => 9,
-                    'rule_label_length' => 2
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['w'],
+                    'rule_list_label_start_pos' => [9],
+                    'rule_list_label_length' => [2]
                    ]);
 
 
@@ -277,8 +277,8 @@ class KohaRecordIntegrationVagabondWithThesaurusOn702DollarATest extends KohaRec
                     'id_thesaurus' => 'AUTH',
                     'id_origine' => null,
                     'code' => 'authors',
-                    'rule_zone' => '702',
-                    'rule_label_field' => 'a']);
+                    'rule_list_zone' => ['702'],
+                    'rule_list_label_field' => ['a']]);
 
 
     $marcel = $this->fixture('Class_CodifThesaurus',
@@ -296,8 +296,8 @@ class KohaRecordIntegrationVagabondWithThesaurusOn702DollarATest extends KohaRec
                             'id_thesaurus' => 'DOCU',
                             'id_origine' => null,
                             'code' => 'document',
-                            'rule_zone' => '099',
-                            'rule_label_field' => 't']);
+                            'rule_list_zone' => ['099'],
+                            'rule_list_label_field' => ['t']]);
 
     $this->fixture('Class_CodifThesaurus',
                    ['id' => 4,
@@ -305,8 +305,8 @@ class KohaRecordIntegrationVagabondWithThesaurusOn702DollarATest extends KohaRec
                     'id_thesaurus' => 'SUMM',
                     'id_origine' => null,
                     'code' => 'summary',
-                    'rule_zone' => '200',
-                    'rule_label_field' => 'g']);
+                    'rule_list_zone' => ['200'],
+                    'rule_list_label_field' => ['g']]);
 
     $this->fixture('Class_CodifThesaurus',
                    ['id' => 5,
@@ -322,8 +322,8 @@ class KohaRecordIntegrationVagabondWithThesaurusOn702DollarATest extends KohaRec
                     'id_thesaurus' => 'TEST',
                     'id_origine' => null,
                     'code' => 'TEST',
-                    'rule_zone' => '610',
-                    'rule_label_field' => 'a']);
+                    'rule_list_zone' => ['610', '995'],
+                    'rule_list_label_field' => ['a', 'e']]);
 
     $loader = $this->onLoaderOfModel('Class_CodifThesaurus');
     $loader
@@ -392,6 +392,13 @@ class KohaRecordIntegrationVagabondWithThesaurusOn702DollarATest extends KohaRec
     $this->assertNotNull(Class_CodifThesaurus::findFirstBy(['id_thesaurus' => 'TEST0001',
                                                             'libelle' => 'Manga']));
   }
+
+
+  /** @test */
+  public function shouldCreateThesaurusFor995_e() {
+    $this->assertNotNull(Class_CodifThesaurus::findFirstBy(['id_thesaurus' => 'TEST0002',
+                                                            'libelle' => 'fiction adulte bande dessinee']));
+  }
 }
 
 
@@ -532,9 +539,9 @@ class KohaRecordIntegrationBdMilleniumWithAuthorityTest extends KohaRecordIntegr
                     'id_thesaurus' => 'MOTC',
                     'id_origine' => null,
                     'code' => 'MOTC',
-                    'rule_zone' => '609',
-                    'rule_label_field' => 'a',
-                    'rule_id_field' => '9']);
+                    'rule_list_zone' => ['609'],
+                    'rule_list_label_field' => ['a'],
+                    'rule_list_id_field' => ['9']]);
 
     $attributs = [[Class_IntProfilDonnees::PROFILE_INDEX_SYSTEMS_FIELDS
                    => [['rule' => '',
@@ -772,11 +779,11 @@ class KohaRecordIntegrationMultipleSECTIntegrationTest extends KohaRecordIntegra
                     'id_thesaurus' => 'SECT',
                     'id_origine' => null,
                     'code' => 'SECT',
-                    'rule_zone' => '099',
-                    'rule_label_field' => 'y',
-                    'rule_id_field' => '',
-                    'rule_filter_field' => '',
-                    'rule_filter_value' => ''
+                    'rule_list_zone' => ['099'],
+                    'rule_list_label_field' => ['y'],
+                    'rule_list_id_field' => [''],
+                    'rule_list_filter_field' => [''],
+                    'rule_list_filter_value' => ['']
                    ]);
 
     $this->fixture('Class_CodifThesaurus',
diff --git a/cosmogramme/tests/php/classes/NanookRecordsIntegrationTest.php b/cosmogramme/tests/php/classes/NanookRecordsIntegrationTest.php
index 864a71fc1723c5438d0c9c261828e792f6e01297..6b4a7f607a0d8b7f8b5f6eed3b846ed39663819f 100644
--- a/cosmogramme/tests/php/classes/NanookRecordsIntegrationTest.php
+++ b/cosmogramme/tests/php/classes/NanookRecordsIntegrationTest.php
@@ -566,11 +566,11 @@ class NanookRecordsIntegrationMultiClassificationTest extends NanookRecordsInteg
                     'id_thesaurus' => 'ESAR',
                     'id_origine' => null,
                     'code' => 'esar',
-                    'rule_zone' => '686',
-                    'rule_label_field' => 't',
-                    'rule_id_field' => 'a',
-                    'rule_filter_field' => '2',
-                    'rule_filter_value' => 'ESAR (Ludothèque)'
+                    'rule_list_zone' => ['686'],
+                    'rule_list_label_field' => ['t'],
+                    'rule_list_id_field' => ['a'],
+                    'rule_list_filter_field' => ['2'],
+                    'rule_list_filter_value' => ['ESAR (Ludothèque)']
                    ]);
 
 
@@ -580,11 +580,11 @@ class NanookRecordsIntegrationMultiClassificationTest extends NanookRecordsInteg
                     'id_thesaurus' => 'JDUR',
                     'id_origine' => null,
                     'code' => 'jduree',
-                    'rule_zone' => '686',
-                    'rule_label_field' => 't',
-                    'rule_id_field' => 'a',
-                    'rule_filter_field' => '2',
-                    'rule_filter_value' => 'Ludo - Durée partie'
+                    'rule_list_zone' => ['686'],
+                    'rule_list_label_field' => ['t'],
+                    'rule_list_id_field' => ['a'],
+                    'rule_list_filter_field' => ['2'],
+                    'rule_list_filter_value' => ['Ludo - Durée partie']
                    ]);
 
     $this->loadRecordsFromFile("unimarc_classifications");
@@ -701,11 +701,11 @@ class NanookRecordsIntegrationExistingRecordWithRemovedClasstificationTest
                     'Id_thesaurus' => 'NIVE',
                     'id_origine' => null,
                     'code' => 'NIVE',
-                    'rule_zone' => '993',
-                    'rule_label_field' => 'a',
-                    'rule_id_field' => '4',
-                    'rule_filter_field' => '',
-                    'rule_filter_value' => '',
+                    'rule_list_zone' => ['993'],
+                    'rule_list_label_field' => ['a'],
+                    'rule_list_id_field' => ['4'],
+                    'rule_list_filter_field' => [''],
+                    'rule_list_filter_value' => [''],
                     'rules' => '{"LabelStartPos":"1","LabelLength":"0","Zone":"993","LabelField":"a","IdField":"4","FilterField":"","FilterValue":""}',
                    ]);
 
@@ -775,9 +775,9 @@ class NanookRecordsIntegrationModifLabelOnDynamicFacetTest extends NanookRecords
                     'id_thesaurus' => 'NIVE',
                     'id_origine' => '',
                     'code' => 'NIVE',
-                    'rule_zone' => '993',
-                    'rule_label_field' => 'a',
-                    'rule_id_field' => '4'
+                    'rule_list_zone' => ['993'],
+                    'rule_list_label_field' => ['a'],
+                    'rule_list_id_field' => ['4']
                    ]);
 
     $this->fixture('Class_CodifThesaurus',
diff --git a/library/Class/CodifThesaurus.php b/library/Class/CodifThesaurus.php
index 1a3b444f91d3df2382fb387fddb81d786d5c4791..177a29561081d93b108f56b55bab8fdf2fba8d85 100644
--- a/library/Class/CodifThesaurus.php
+++ b/library/Class/CodifThesaurus.php
@@ -201,17 +201,18 @@ class CodifThesaurusLoader extends Storm_Model_Loader {
 
     $zone = $parts[0];
     $label_field = $parts[1];
-    $rules = (new Class_CodifThesaurus_Rules())
-      ->setZone($zone)
-      ->setLabelField($label_field);
 
-    if (Class_CodifThesaurus::findFirstBy(['rules' => $rules->format()]))
+    $list_rules = (new Class_CodifThesaurus_ListRules())
+      ->setListZone([$zone])
+      ->setListLabelField([$label_field]);
+
+    if (Class_CodifThesaurus::findFirstBy(['rules' => $list_rules->format()]))
       return ;
 
     Class_CodifThesaurus::newInstance(['libelle'          => $facet_name,
                                        'libelle_facette'  => $facet_name,
-                                       'rule_zone'        => $zone,
-                                       'rule_label_field' => $label_field])
+                                       'rule_list_zone'   => [$zone],
+                                       'rule_list_label_field' => [$label_field]])
       ->save();
   }
 
@@ -437,7 +438,7 @@ class CodifThesaurusLoader extends Storm_Model_Loader {
 
   protected function getCustomFieldsFacetPrefix() {
     if (!isset($this->_customfields_facet_prefix))
-        return $this->_customfields_facet_prefix = Class_CodifThesaurus::CODE_FACETTE . Class_CodifThesaurus::fixedIdOf('CustomField');
+      return $this->_customfields_facet_prefix = Class_CodifThesaurus::CODE_FACETTE . Class_CodifThesaurus::fixedIdOf('CustomField');
     return $this->_customfields_facet_prefix;
   }
 
@@ -557,7 +558,7 @@ class CodifThesaurusLoader extends Storm_Model_Loader {
                                                                  'rules not' => '',
                                                                  'id_thesaurus not' => null,
                                                                  'order' => 'libelle'])))
-      ->select('hasRuleIdField')
+      ->select('hasRuleListIdField')
       ->eachDo($closure);
   }
 
@@ -591,8 +592,7 @@ class Class_CodifThesaurus extends Storm_Model_Abstract {
                                           'rules' => null,
                                           'code' => null];
 
-  protected $_rules;
-
+  protected $_list_rules;
 
   public static function facetLabelFor($id) {
     return ($thesaurus = static::getLoader()->findFirstBy(['id_thesaurus' => $id]))
@@ -601,110 +601,113 @@ class Class_CodifThesaurus extends Storm_Model_Abstract {
   }
 
 
-  public function __construct() {
-    parent::__construct();
-    $this->_rules = new Class_CodifThesaurus_Rules();
+  public function beforeSave() {
+    $this->setRules($this->_getListRules()->format());
   }
 
 
-  public function initializeAttributes($datas) {
-    parent::initializeAttributes($datas);
-    $this->_rules->initialize($this->getRules());
+  public function updateAttributes(Array $datas) {
+    parent::updateAttributes($datas);
+    $this->_getListRules()->clean();
     return $this;
   }
 
 
-  public function beforeSave() {
-    $this->setRules($this->_rules->format());
+  public function getRuleListZone() {
+    return $this->_getListRules()->getListZone();
   }
 
 
-  public function getRuleZone() {
-    return $this->_rules->getZone();
+  public function getRuleListLabelField() {
+    return $this->_getListRules()->getListLabelField();
   }
 
 
-  public function setRuleZone($zone) {
-    $this->_rules->setZone($zone);
-    return $this;
+  public function getRuleListIdField() {
+    return $this->_getListRules()->getListIdField();
   }
 
 
-  public function getRuleLabelField() {
-    return $this->_rules->getLabelField();
+  public function getRuleListFilterField() {
+    return $this->_getListRules()->getListFilterField();
   }
 
 
-  public function setRuleLabelField($field) {
-    $this->_rules->setLabelField($field);
-    return $this;
+  public function getRuleListFilterValue() {
+    return $this->_getListRules()->getListFilterValue();
   }
 
 
-  public function getRuleIdField() {
-    return $this->_rules->getIdField();
+  public function getRuleListLabelLength() {
+    return $this->_getListRules()->getListLabelLength();
   }
 
 
-  public function setRuleIdField($field) {
-    $this->_rules->setIdField($field);
-    return $this;
+  public function getRuleListLabelStartPos() {
+    return $this->_getListRules()->getListLabelStartPos();
   }
 
 
-  public function setRuleLabelStartPos($value) {
-    $this->_rules->setLabelStartPos($value);
+  public function setRuleListZone($values) {
+    $this->_getListRules()->setListZone($values);
     return $this;
   }
 
 
-  public function setRuleFilterField($field) {
-    $this->_rules->setFilterField($field);
+  public function setRuleListLabelField($values) {
+    $this->_getListRules()->setListLabelField($values);
     return $this;
   }
 
 
-  public function setRuleFilterValue($field) {
-    $this->_rules->setFilterValue($field);
+  public function setRuleListIdField($values) {
+    $this->_getListRules()->setListIdField($values);
     return $this;
   }
 
 
+  public function setRuleListLabelStartPos($values) {
+    $this->_getListRules()->setListLabelStartPos($values);
+    return $this;
+  }
+
 
-  public function setRuleLabelLength($value) {
-    $this->_rules->setLabelLength($value);
+  public function setRuleListFilterField($values) {
+    $this->_getListRules()->setListFilterField($values);
     return $this;
   }
 
 
-  public function getRuleLabelLength() {
-    return $this->_rules->getLabelLength();
+  public function setRuleListFilterValue($values) {
+    $this->_getListRules()->setListFilterValue($values);
+    return $this;
   }
 
 
-  public function getRuleLabelStartPos() {
-    return $this->_rules->getLabelStartPos();
+  public function setRuleListLabelLength($values) {
+    $this->_getListRules()->setListLabelLength($values);
+    return $this;
   }
 
 
   public function rulesTruncateLabels($labels) {
-    return $this->_rules->truncateLabels($labels);
+    return $this->_getListRules()->truncateLabels($labels);
   }
 
 
   public function getRulesAsArray() {
-    return ['rule_zone' => $this->_rules->getZone(),
-            'rule_label_field' => $this->_rules->getLabelField(),
-            'rule_id_field' => $this->_rules->getIdField(),
-            'rule_label_start_pos' => $this->_rules->getLabelStartPos(),
-            'rule_label_length' => $this->_rules->getLabelLength(),
-            'rule_filter_field' => $this->_rules->getFilterField(),
-            'rule_filter_value' => $this->_rules->getFilterValue()];
+    return ['rule_list_zone' => $this->getRuleListZone(),
+            'rule_list_label_field' => $this->getRuleListLabelField(),
+            'rule_list_id_field' => $this->getRuleListIdField(),
+            'rule_list_label_start_pos' => $this->getRuleListLabelStartPos(),
+            'rule_list_label_length' => $this->getRuleListLabelLength(),
+            'rule_list_filter_field' => $this->getRuleListFilterField(),
+            'rule_list_filter_value' => $this->getRuleListFilterValue()];
   }
 
 
   public function withLabelAndIdRulesDo($closure) {
-    return $this->_rules->withLabelAndIdDo($closure);
+    return $this->_getListRules()->withLabelAndIdListRulesDo($closure);
   }
 
 
@@ -727,9 +730,7 @@ class Class_CodifThesaurus extends Storm_Model_Abstract {
   public function newChildEntry() {
     $code = $this->getCode();
     return Class_CodifThesaurus::getLoader()->newInstance(['code' => $code,
-                                                           'id_thesaurus' => Class_CodifThesaurus::getLoader()->findNextThesaurusChildId(
-                                                                                                                                         $code,
-                                                                                                                                         $this->getIdThesaurus())]);
+                                                           'id_thesaurus' => Class_CodifThesaurus::getLoader()->findNextThesaurusChildId($code, $this->getIdThesaurus())]);
   }
 
 
@@ -740,7 +741,7 @@ class Class_CodifThesaurus extends Storm_Model_Abstract {
     if ($label == $entry->getLibelle())
       return $entry;
 
-    $entry ->updateAttributes(['id_origine' => $id_origine,
+    $entry->updateAttributes(['id_origine' => $id_origine,
                                'libelle' => $label]);
 
     return $entry->save() ? $entry : null;
@@ -767,16 +768,7 @@ class Class_CodifThesaurus extends Storm_Model_Abstract {
 
 
   public function withRulesDo($closure) {
-    if ((!$this->_rules->getZone())
-        || (!$this->_rules->getLabelField()))
-      return;
-
-    return $closure($this->_rules);
-  }
-
-
-  public function rulesCanHandle($reader)  {
-    return $this->_rules->canHandle($reader);
+    return $this->_getListRules()->withRulesDo($closure);
   }
 
 
@@ -785,7 +777,21 @@ class Class_CodifThesaurus extends Storm_Model_Abstract {
 
     $this->checkAttribute('libelle', '' != $this->getLibelle(), $this->_('Vous devez définir le libellé'));
 
-    $this->check($this->_rules->isValid(), $this->_rules->getErrorMessage());
+    $this->_getListRules()->validate($this);
+  }
+
+
+  public function existsRulesByZoneLabel($zone, $label) {
+    return $this->_getListRules()->existsByZoneLabel($zone, $label);
+  }
+
+
+  protected function _getListRules() {
+    if ($this->_list_rules)
+      return $this->_list_rules;
+
+    return $this->_list_rules = (new Class_CodifThesaurus_ListRules())
+      ->initialize($this->getRules());
   }
 
 
@@ -917,10 +923,19 @@ class Class_CodifThesaurus extends Storm_Model_Abstract {
   }
 
 
+  public function hasRuleListIdField()  {
+    return !$this->_getListRules()->isIdFieldsEmpty();
+  }
+
+
+  public function getLabelFromZoneIdField() {
+    return $this->_getListRules()->getLabelFromZoneIdField();
+  }
+
+
   public function authoritiesIndexSystems() {
-    if (!$this->getRuleIdField())
+    if (!$this->hasRuleListIdField())
       return [];
-
     $systems = [];
 
     foreach(Class_IntProfilDonnees::findAllOfTypeAuthority() as $profile)
diff --git a/library/Class/CodifThesaurus/ListRules.php b/library/Class/CodifThesaurus/ListRules.php
new file mode 100644
index 0000000000000000000000000000000000000000..4fd967470ab8ab9352c580cf07fc9545fc2823be
--- /dev/null
+++ b/library/Class/CodifThesaurus/ListRules.php
@@ -0,0 +1,238 @@
+<?php
+/**
+ * Copyright (c) 2012-2021, 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_CodifThesaurus_ListRules {
+
+  protected $_list_rules;
+
+  public function __construct() {
+    $this->_list_rules = new Storm_Collection();
+  }
+
+
+  public function initialize($datas) {
+    if (!$rules = json_decode($datas, true))
+      return $this;
+
+    if (!is_array($rules[0]))
+      $rules = [ $rules ];
+
+    foreach ($rules as $rule) {
+      $new_rule = new Class_CodifThesaurus_Rules();
+      $new_rule->initializeFields($rule);
+      $this->_list_rules->add($new_rule);
+    }
+
+    return $this;
+  }
+
+
+  public function clean() {
+    $this->_list_rules = $this->_withNotEmpty();
+    return $this;
+  }
+
+
+  public function format() {
+    $list_format = $this->_withNotEmpty()
+      ->collect(function ($rules)
+                {
+                  return $rules->asArray();
+                })
+      ->getArrayCopy();
+
+    return $list_format
+      ? json_encode($list_format)
+      : null;
+  }
+
+
+  public function withLabelAndIdListRulesDo($closure) {
+    return $this->_injectIntoDo(function ($result, $rules) use ($closure)
+                                {
+                                  return array_merge($result, $rules->withLabelAndIdDo($closure));
+                                });
+  }
+
+
+  public function withRulesDo($closure) {
+    return $this->_injectIntoDo(function ($result, $rules) use ($closure)
+                                {
+                                  return array_merge($result, $closure($rules));
+                                });
+  }
+
+
+  public function isIdFieldsEmpty() {
+    return 0 == count(array_filter($this->getListIdField()));
+  }
+
+
+  public function existsByZoneLabel($zone, $label) {
+    return 0 < $this->_list_rules->select(function ($rules) use ($zone, $label)
+                                          {
+                                            return $zone === $rules->getZone()
+                                              && $label === $rules->getLabelField();
+                                          })
+                                 ->count();
+  }
+
+
+  public function validate($codif_thesaurus) {
+    $this->_withNotEmpty()
+         ->eachDo(function ($rules) use ($codif_thesaurus)
+                  {
+                    $codif_thesaurus->check($rules->isValid(), $rules->getErrorMessage());
+                  });
+    return $this;
+  }
+
+
+  public function getLabelFromZoneIdField() {
+    return implode('', $this->_list_rules
+                   ->select(function ($rules)
+                            {
+                              return $rules->getIdField();
+                            })
+                   ->collect(function ($rules)
+                             {
+                               return sprintf(' (%s$%s)', $rules->getZone(), $rules->getIdField());
+                             })
+                   ->getArrayCopy());
+  }
+
+
+  public function getListZone() {
+    return $this->_getFromList('Zone');
+  }
+
+
+  public function getListLabelField() {
+    return $this->_getFromList('LabelField');
+  }
+
+
+  public function getListIdField() {
+    return $this->_getFromList('IdField');
+  }
+
+
+  public function getListLabelStartPos() {
+    return $this->_getFromList('LabelStartPos');
+  }
+
+
+  public function getListLabelLength() {
+    return $this->_getFromList('LabelLength');
+  }
+
+
+  public function getListFilterField() {
+    return $this->_getFromList('FilterField');
+  }
+
+
+  public function getListFilterValue() {
+    return $this->_getFromList('FilterValue');
+  }
+
+
+  public function setListZone($values) {
+    return $this->_setFromList('Zone', $values);
+  }
+
+
+  public function setListLabelField($values) {
+    return $this->_setFromList('LabelField', $values);
+  }
+
+
+  public function setListIdField($values) {
+    return $this->_setFromList('IdField', $values);
+  }
+
+
+  public function setListLabelStartPos($values) {
+    return $this->_setFromList('LabelStartPos', $values);
+  }
+
+
+  public function setListLabelLength($values) {
+    return $this->_setFromList('LabelLength', $values);
+  }
+
+
+  public function setListFilterField($values) {
+    return $this->_setFromList('FilterField', $values);
+  }
+
+
+  public function setListFilterValue($values) {
+    return $this->_setFromList('FilterValue', $values);
+  }
+
+
+  protected function _getFromList($field) {
+    return $this->_list_rules->collect(function($rules) use($field)
+                                       {
+                                         return call_user_func([$rules, 'get' . $field]);
+                                       })
+                             ->getArrayCopy();
+  }
+
+
+  protected function _setFromList($name, $fields) {
+    if ($this->_list_rules->count() > count($fields))
+      $this->_list_rules = new Storm_Collection();
+
+    $name = 'set' . $name;
+    foreach ($fields as $pos => $value)
+      $this->_getOrCreateRules($pos)->$name($value);
+    return $this;
+  }
+
+
+  protected function _withNotEmpty() {
+    return $this->_list_rules
+      ->reject(function ($rules)
+               {
+                 return $rules->isEmpty();
+               });
+  }
+
+
+  protected function _injectIntoDo($closure) {
+    return $this->_withNotEmpty()
+                ->injectInto([], $closure);
+  }
+
+
+  protected function _getOrCreateRules($position) {
+    if ($this->_list_rules->count() > $position
+        && $rules = $this->_list_rules->offsetGet($position))
+      return $rules;
+
+    $rules = new Class_CodifThesaurus_Rules();
+    $this->_list_rules->add($rules);
+    return $rules;
+  }
+}
\ No newline at end of file
diff --git a/library/Class/CodifThesaurus/Rules.php b/library/Class/CodifThesaurus/Rules.php
index 98ae173f5694a3b40e36cfacc80c5541229d05b9..c8832e21a87cf50d7be5e3c4830088ecac796f2b 100644
--- a/library/Class/CodifThesaurus/Rules.php
+++ b/library/Class/CodifThesaurus/Rules.php
@@ -35,13 +35,12 @@ class Class_CodifThesaurus_Rules extends Class_Entity {
                             'FilterValue'];
 
 
-  public function initialize($datas) {
-    if (!$rules = json_decode($datas, true))
-      return;
-
+  public function initializeFields($rules) {
     foreach($this->_persistent_attribs as $field)
       if (isset($rules[$field]))
         $this->_attribs[$field] = $rules[$field];
+
+    return $this;
   }
 
 
@@ -191,4 +190,4 @@ class Class_CodifThesaurus_Rules extends Class_Entity {
   public function getZonePadded() {
     return sprintf('%03d', trim($this->getZone()));
   }
-}
+}
\ No newline at end of file
diff --git a/library/Class/Exemplaire/Fields.php b/library/Class/Exemplaire/Fields.php
index a4c98163a04b27661103eae2d009b4935d57b809..13cce0f18b343844b2dbc70858dcc1dcce23efb8 100644
--- a/library/Class/Exemplaire/Fields.php
+++ b/library/Class/Exemplaire/Fields.php
@@ -140,7 +140,7 @@ class Class_Exemplaire_Fields {
       return null;
 
     foreach (Class_CodifThesaurus::findAllDynamicFacets() as $thesaurus)
-      if ($thesaurus->getRuleZone() == $item_zone && $thesaurus->getRuleLabelField() == $subfield)
+      if ($thesaurus->existsRulesByZoneLabel($item_zone, $subfield))
         return $thesaurus;
 
     return null;
diff --git a/library/Class/ProfileSerializer/UnimarcAuthority.php b/library/Class/ProfileSerializer/UnimarcAuthority.php
index 24b1ee65d5c750854339e7bfe1f98d22fa983d5a..790606a9a00ff31770360d1b487170b4e4dc9537 100644
--- a/library/Class/ProfileSerializer/UnimarcAuthority.php
+++ b/library/Class/ProfileSerializer/UnimarcAuthority.php
@@ -69,9 +69,7 @@ class Class_ProfileSerializer_UnimarcAuthority extends Class_ProfileSerializer_A
   protected function _buildThesaurusOptions() {
     $options = [0 => ''];
     $collector = function($model) use (&$options) {
-      $label = $model->getLibelle() . sprintf(' (%s$%s)',
-                                              $model->getRuleZone(), $model->getRuleIdfield());
-      $options[$model->getId()] = $label;
+      $options[$model->getId()] = $model->getLibelle() . $model->getLabelFromZoneIdField();
     };
 
     Class_CodifThesaurus::withDynamicFacetsHavingIdFieldDo($collector);
diff --git a/library/ZendAfi/Form/Admin/DynamicFacet.php b/library/ZendAfi/Form/Admin/DynamicFacet.php
index 730bbd93295ce386b61c2c9ab7fcb1d573f596e4..040946c570485e8484ed6349e7dce6b725fc664a 100644
--- a/library/ZendAfi/Form/Admin/DynamicFacet.php
+++ b/library/ZendAfi/Form/Admin/DynamicFacet.php
@@ -25,14 +25,6 @@ class ZendAfi_Form_Admin_DynamicFacet extends ZendAfi_Form {
   public function init() {
     parent::init();
 
-    $field_options = ['' => '',
-                      '#' => '$0'];
-    foreach(range(1, 9) as $field)
-      $field_options[(string) $field] = '$'.$field;
-
-    foreach(range('a', 'z') as $field)
-      $field_options[$field] = '$'.$field;
-
     $this
       ->addElement('text',
                    'libelle',
@@ -40,68 +32,47 @@ class ZendAfi_Form_Admin_DynamicFacet extends ZendAfi_Form {
                     'required' => true,
                     'allowEmpty' => false])
 
-
       ->addElement('text',
                    'libelle_facette',
                    ['label' => $this->_('Libellé dans le résultat de recherche')])
 
+      ->addElement('text',
+                   'code',
+                   ['label' => $this->_('Code'),
+                    'disabled' => 'disabled'])
 
       ->addElement('text',
-                   'rule_zone',
-                   ['label' => $this->_('Zone'),
-                    'size' => 3,
-                    'maxlength' => 3,
-                    'required' => true,
-                    'allowEmpty' => false,
-                    'validators' => [(new Zend_Validate_Regex('/^[0-9]{3}$/'))
-                                     ->setMessage($this->_('La zone doit être composée de 3 chiffres (001, 015, etc...)'))]])
-
-      ->addElement('select',
-                   'rule_label_field',
-                   ['label' => $this->_('Prendre le libellé en'),
-                    'multiOptions' => $field_options,
-                    'required' => true,
-                    'allowEmpty' => false])
+                   'id_thesaurus',
+                   ['label' => $this->_('Identifiant thésaurus'),
+                    'disabled' => 'disabled'])
 
-      ->addElement('number',
-                   'rule_label_start_pos',
-                   ['label' => $this->_('Position du premier caractère du libellé'),
-                    'required' => true,
-                    'allowEmpty' => false,
-                    'min' => 1])
+      ->addElement((new ZendAfi_Form_Admin_DynamicFacetRules())->getElement());
 
-      ->addElement('number',
-                   'rule_label_length',
-                   ['label' => $this->_('Longueur du libellé (0 pour prendre totalité du libellé)'),
-                    'required' => true,
-                    'allowEmpty' => false,
-                    'min' => 0])
+    $this->addUniqDisplayGroup('thesauri');
+  }
 
-      ->addElement('select',
-                   'rule_id_field',
-                   ['label' => $this->_('Prendre l\'identifiant/indice en'),
-                    'multiOptions' => $field_options])
 
+  public function populate(array $values) {
+    parent::populate($values);
+    if (!$multi_rules = $this->getElement(ZendAfi_Form_Admin_DynamicFacetRules::MULTI_RULES))
+      return $this;
 
-      ->addElement('select',
-                   'rule_filter_field',
-                   ['label' => $this->_('Filtrer l\'application de la facette par le champ'),
-                    'multiOptions' => $field_options])
+    $multi_rules->setValues(['rule_list_zone' => $values['rule_list_zone'],
+                             'rule_list_label_field' => $values['rule_list_label_field'],
+                             'rule_list_id_field' => $values['rule_list_id_field'],
+                             'rule_list_label_start_pos' => $values['rule_list_label_start_pos'],
+                             'rule_list_label_length' => $values['rule_list_label_length'],
+                             'rule_list_filter_field' => $values['rule_list_filter_field'],
+                             'rule_list_filter_value' => $values['rule_list_filter_value']]);
 
-      ->addElement('text',
-                   'rule_filter_value',
-                   ['label' => $this->_('Le champ de filtrage doit contenir la valeur')])
+    return $this;
+  }
 
-      ->addElement('text',
-                   'code',
-                   ['label' => $this->_('Code'),
-                    'disabled' => 'disabled'])
 
-      ->addElement('text',
-                   'id_thesaurus',
-                   ['label' => $this->_('Identifiant thésaurus'),
-                    'disabled' => 'disabled'])
+  public function isValidModelAndArray($model, $array) {
+    foreach($model->getRulesAsArray() as $rules => $value)
+      $array[$rules] = $value;
 
-      ->addUniqDisplayGroup('thesauri');
+    return parent::isValidModelAndArray($model, $array);
   }
 }
\ No newline at end of file
diff --git a/library/ZendAfi/Form/Admin/DynamicFacetRules.php b/library/ZendAfi/Form/Admin/DynamicFacetRules.php
new file mode 100644
index 0000000000000000000000000000000000000000..46b79a6fd254b077207f399304565a2f5a1bb347
--- /dev/null
+++ b/library/ZendAfi/Form/Admin/DynamicFacetRules.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Copyright (c) 2012-2021, 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 ZendAfi_Form_Admin_DynamicFacetRules {
+  use Trait_Translator;
+
+  const MULTI_RULES = 'multi_rules';
+
+  protected
+    $_multi_rules,
+    $_fields_options;
+
+  public function __construct() {
+    $this->_initRulesMultiInput()
+         ->_addValidators();
+  }
+
+
+  public function getElement() {
+    return $this->_multi_rules;
+  }
+
+
+  protected function _initRulesMultiInput() {
+    $rules = new Class_CodifThesaurus_Rules();
+
+    $fields = [];
+    $fields [] = ['name' => 'rule_list_zone',
+                  'label' => $this->_('Zone'),
+                  'attribs' => ['size' => 3,
+                                'maxlength' => 3,
+                                'style' => 'width:auto;']];
+    $fields [] = ['name' => 'rule_list_label_field',
+                  'label' => $this->_('Libellé'),
+                  'type' => 'select',
+                  'attribs' => ['style' => 'width:auto;'],
+                  'options' => $this->_getFieldsOptions()];
+    $fields [] = ['name' => 'rule_list_label_start_pos',
+                  'type' => 'number',
+                  'label' => $this->_('Position du libellé'),
+                  'default_value' => $rules->getLabelStartPos(),
+                  'attribs' => ['min' => 1,
+                                'size' => 3,
+                                'style' => 'width:auto;']];
+    $fields [] = ['name' => 'rule_list_label_length',
+                  'type' => 'number',
+                  'label' => $this->_('Longueur du libellé (0 = total)'),
+                  'default_value' => $rules->getLabelLength(),
+                  'attribs' => ['min' => 0,
+                                'size' => 3,
+                                'style' => 'width:auto;']];
+    $fields [] = ['name' => 'rule_list_id_field',
+                  'type' => 'select',
+                  'label' => $this->_('Identifiant/Indice'),
+                  'attribs' => ['style' => 'width:auto;'],
+                  'options' => $this->_getFieldsOptions()];
+    $fields [] = ['name' => 'rule_list_filter_field',
+                  'type' => 'select',
+                  'label' => $this->_('Filtrer la facette par le champ'),
+                  'attribs' => ['style' => 'width:auto;'],
+                  'options' => $this->_getFieldsOptions()];
+    $fields [] = ['name' => 'rule_list_filter_value',
+                  'label' => $this->_('Champ de filtrage contient')];
+
+    $this->_multi_rules = new ZendAfi_Form_Element_MultiInput(static::MULTI_RULES,
+                                                              ['label' => $this->_('Règles'),
+                                                               'fields' => $fields]);
+    return $this;
+  }
+
+
+  protected function _getFieldsOptions() {
+    if ($this->_fields_options)
+      return $this->_fields_options;
+
+    $this->_fields_options = ['' => '',
+                              '#' => '$0'];
+
+    foreach (range(1, 9) as $field)
+      $this->_fields_options[(string) $field] = '$' . $field;
+
+    foreach (range('a', 'z') as $field)
+      $this->_fields_options[$field] = '$' . $field;
+
+    return $this->_fields_options;
+  }
+
+
+  protected function _addValidators() {
+    $this->_multi_rules
+      ->setFieldsValidators(['rule_list_zone' =>
+                             [(new Zend_Validate_Regex('/^[0-9]{3}$/'))
+                              ->setMessage($this->_('La zone doit être composée de 3 chiffres (001, 015, etc...)'))]]);
+    return $this;
+  }
+}
diff --git a/library/ZendAfi/Form/Element/MultiInput.php b/library/ZendAfi/Form/Element/MultiInput.php
index bff5656b8428417d8d341b2e87bc3b200c8d4f53..934512560577147d627eaf287d4ffd7048d18a62 100644
--- a/library/ZendAfi/Form/Element/MultiInput.php
+++ b/library/ZendAfi/Form/Element/MultiInput.php
@@ -36,6 +36,7 @@ class ZendAfi_Form_Element_MultiInput extends Zend_Form_Element {
     foreach ($decorators as $name => $value)
       $this->_decorators[$name] = $value;
     $this->removeDecorator('ViewHelper');
+    $this->addValidator(new ZendAfi_Validate_MultiInput());
   }
 
 
diff --git a/library/ZendAfi/Validate/MultiInput.php b/library/ZendAfi/Validate/MultiInput.php
new file mode 100644
index 0000000000000000000000000000000000000000..2c2a09df01830f542970be92e1f0d511157dca2d
--- /dev/null
+++ b/library/ZendAfi/Validate/MultiInput.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Copyright (c) 2012-2021, 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 ZendAfi_Validate_MultiInput extends Zend_Validate_Abstract {
+  const MULTI_INPUT_SIZE = 'multiInputSize';
+
+  protected
+    $_last_size,
+    $_messageTemplates =
+    [ self::MULTI_INPUT_SIZE => "La taille des elements de ce multi input n'est pas conforme." ];
+
+  public function isValid($value) {
+    if (!$value || !is_array($value) || 1 == count($value))
+      return true;
+
+    $this->_last_size = null;
+    foreach ($value as $list_val)
+      if ($this->_isWithErrorSizes($list_val))
+        return false;
+
+    return true;
+  }
+
+
+  protected function _isWithErrorSizes($list_val) {
+    if (!$list_val || !is_array($list_val))
+      return false;
+
+    $size = count($list_val);
+    if (null !== $this->_last_size && $this->_last_size !== $size) {
+      $this->_error(self::MULTI_INPUT_SIZE);
+      return true;
+    }
+
+    $this->_last_size = $size;
+    return false;
+  }
+}
diff --git a/public/admin/js/multi_inputs/multi_inputs.js b/public/admin/js/multi_inputs/multi_inputs.js
index 9a0b88ff58ae8796312f6c2fad2db176efafdc64..f06a105e83a295d9687e6acc886fa9171aea66ba 100644
--- a/public/admin/js/multi_inputs/multi_inputs.js
+++ b/public/admin/js/multi_inputs/multi_inputs.js
@@ -75,14 +75,22 @@
                        + '<li>' + options.line_errors[value_index].join('</li><li>') + '</li></ul></td></tr>');
       },
 
+      field_get_value: function(options, value_index, input) {
+        if (null != value_index
+            && value_index < options.values[input.name].length)
+          return options.values[input.name][value_index];
+
+        return undefined != input.default_value
+          ? input.default_value
+          : '';
+      },
+
       field_add: function(options, key, value_index) {
         var input = options.fields[key];
         if ('placeholder' == input.type)
           return '<td style="vertical-align:top;" data-multiinputs-field="' + input.name + '"></td>';
 
-        var value = (null != value_index && value_index < options.values[input.name].length)
-            ? options.values[input.name][value_index]
-            : '';
+        var value = this.field_get_value(options, value_index, input);
         
         var desc = (null != value_index
                     && null != options.descs
@@ -90,10 +98,10 @@
                     && value_index < options.descs[input.name].length)
             ? options.descs[input.name][value_index]
             : '';
-        
+
         var html = input.type == 'select'
             ? '<select></select>'
-            : '<input type="text" />';
+            : '<input type="' + (input.type || 'text') + '" />';
         
         var node = $(html).attr('name', input.name + '[]');
 
@@ -104,7 +112,7 @@
         
         for (var attrib_name in input.attribs)
           if (input.attribs.hasOwnProperty(attrib_name))
-            node.attr(attrib_name,input.attribs[attrib_name]);
+            node.attr(attrib_name, input.attribs[attrib_name]);
 
         return '<td style="vertical-align:top;">'
           + $('<div/>').append( node ).append(desc).html() + '</td>';
diff --git a/public/admin/js/multi_inputs/test.js b/public/admin/js/multi_inputs/test.js
index 420cc9679fd7d22432e8f34ef4503c5a905ec777..a1b9cae12f9a13298511d6292781b85e4e34f5e9 100644
--- a/public/admin/js/multi_inputs/test.js
+++ b/public/admin/js/multi_inputs/test.js
@@ -162,3 +162,30 @@ test('onchange', function() {
   $(element).change();
   equal(ajax_calls[0], 'http://mysuperurl.fr/val/author', 'URL has been called ' + ajax_calls[0]);
 });
+
+
+test('one input with type number', function() {
+  var insertion_point = call_multi_inputs_for({
+    fields:[{name:'testing', type:'number'}], 
+    values:{testing:[]}
+  });
+  equal(insertion_point.find('input[name="testing[]"][type="number"]').length, 1, '1 input with number type');
+});
+
+
+test('one input with default type text', function() {
+  var insertion_point = call_multi_inputs_for({
+    fields:[{name:'testing'}], 
+    values:{testing:[]}
+  });
+  equal(insertion_point.find('input[name="testing[]"][type="text"]').length, 1, '1 input with default type text');
+});
+
+
+test('input with default value', function() {
+  var insertion_point = call_multi_inputs_for({
+    fields:[{name:'testing',default_value:'3'}], 
+    values:{testing:[]}
+  });
+  equal(insertion_point.find('input[name="testing[]"][type="text"][value="3"]').length, 1, '1 input with default value 3');
+});
diff --git a/tests/application/modules/opac/controllers/NoticeAjaxControllerItemsTest.php b/tests/application/modules/opac/controllers/NoticeAjaxControllerItemsTest.php
index e8a62fbe34f7284d5f4e33fbacb805abb493d313..cb78590d048e37aafe35510a76ff1ce1e2e5c475 100644
--- a/tests/application/modules/opac/controllers/NoticeAjaxControllerItemsTest.php
+++ b/tests/application/modules/opac/controllers/NoticeAjaxControllerItemsTest.php
@@ -135,8 +135,8 @@ class NoticeAjaxControllerItemsWithoutOrderTest
                     'libelle_facette' => 'Emplacement',
                     'code' => 'Emplacement',
                     'id_thesaurus' => 'EMPL',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 'e'])
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['e']])
          ->getOrCreateChild('EMPL1', 'Chambre');
 
     Class_Profil::getCurrentProfil()->setCfgNotice($config);
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index a8f33109dccc3a6c4bcb0f6373ece7426e1713d4..6a1f4201d64de154dc5f75c0b853e37c1834186f 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -3722,4 +3722,19 @@ class UpgradeDB_405_Test extends UpgradeDBTestCase {
   public function sessionActivityDateLimiteDebutShouldBeNullable() {
     $this->assertFieldNullable('session_activity', 'date_limite_debut');
   }
+}
+
+
+
+
+class UpgradeDB_406_Test extends UpgradeDBTestCase {
+  public function prepare() {
+    $this->silentQuery('ALTER TABLE `codif_thesaurus` MODIFY `rules` varchar(250)');
+  }
+
+
+  /** @test */
+  public function tableCodifThesaurusShouldHaveColumnRulesWithTypeText() {
+    $this->assertFieldType('codif_thesaurus', 'rules', 'text');
+  }
 }
\ No newline at end of file
diff --git a/tests/library/ZendAfi/Form/MultiInputTest.php b/tests/library/ZendAfi/Form/MultiInputTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..179b53f5fa0558beff946d3c19160cad567de4a7
--- /dev/null
+++ b/tests/library/ZendAfi/Form/MultiInputTest.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright (c) 2012-2021, 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 ZendAfi_Form_MultiInputTest extends ModelTestCase {
+
+  protected $_multi_input;
+
+  public function setUp() {
+    parent::setUp();
+    Storm_Model_Loader::defaultToVolatile();
+
+    $fields = [['name' => 'input_text_1',
+                'label' => 'Champ 1']];
+    $fields [] = ['name' => 'input_text_2',
+                  'label' => 'Champ 2'];
+    $this->_multi_input = new ZendAfi_Form_Element_MultiInput('test_multi_input',
+                                                              ['fields' => $fields]);
+  }
+
+
+  /** @test */
+  public function validateMultiInputShouldBeFalse() {
+    $this->assertFalse($this->_multi_input
+                       ->isValid(null,
+                                 ['input_text_1' => ['text1', 'text2'],
+                                  'input_text_2' => ['text3']]));
+  }
+}
diff --git a/tests/scenarios/AdvancedSearch/AdvancedSearchTest.php b/tests/scenarios/AdvancedSearch/AdvancedSearchTest.php
index a5cb3d0571376f55b893169cd4c3a7f879340f3f..439689a8f4d4dea8ead9e7e1e908f1b55d32f172 100644
--- a/tests/scenarios/AdvancedSearch/AdvancedSearchTest.php
+++ b/tests/scenarios/AdvancedSearch/AdvancedSearchTest.php
@@ -411,10 +411,10 @@ class AdvancedSearchFormWithDateSelectorsTest extends AdvancedSearchCustomFormSe
                     'id_thesaurus' => 'APUB',
                     'id_origine' => null,
                     'code' => 'APUB',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 'w',
-                    'rule_label_start_pos' => 1,
-                    'rule_label_length' => 4
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['w'],
+                    'rule_list_label_start_pos' => [1],
+                    'rule_list_label_length' => [4]
                    ]);
 
 
@@ -424,10 +424,10 @@ class AdvancedSearchFormWithDateSelectorsTest extends AdvancedSearchCustomFormSe
                     'id_thesaurus' => 'MPUB',
                     'id_origine' => null,
                     'code' => 'MPUB',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 'w',
-                    'rule_label_start_pos' => 6,
-                    'rule_label_length' => 2
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['w'],
+                    'rule_list_label_start_pos' => [6],
+                    'rule_list_label_length' => [2]
                    ]);
 
     $this->fixture('Class_CodifThesaurus',
@@ -436,10 +436,10 @@ class AdvancedSearchFormWithDateSelectorsTest extends AdvancedSearchCustomFormSe
                     'id_thesaurus' => 'JPUB',
                     'id_origine' => null,
                     'code' => 'JPUB',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 'w',
-                    'rule_label_start_pos' => 9,
-                    'rule_label_length' => 2
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['w'],
+                    'rule_list_label_start_pos' => [9],
+                    'rule_list_label_length' => [2]
                    ]);
 
     $this->fixture('Class_CodifThesaurus',
@@ -816,8 +816,8 @@ class AdvancedSearchMultiFacetsPostDispatchTest extends Admin_AbstractController
                     'id_thesaurus' => 'DOCU',
                     'id_origine' => null,
                     'code' => 'DOCU',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 't']);
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['t']]);
 
     $this->fixture('Class_CodifThesaurus',
                    ['id' => 4,
@@ -826,8 +826,8 @@ class AdvancedSearchMultiFacetsPostDispatchTest extends Admin_AbstractController
                     'id_thesaurus' => 'DOCU0001',
                     'id_origine' => null,
                     'code' => 'DOCU',
-                    'rule_zone' => '999',
-                    'rule_label_field' => 't']);
+                    'rule_list_zone' => ['999'],
+                    'rule_list_label_field' => ['t']]);
   }
 
 
diff --git a/tests/scenarios/Authorities/AuthoritiesTest.php b/tests/scenarios/Authorities/AuthoritiesTest.php
index 99c1c2ee4945b073b08ad276a939230b26511b3a..890849575a5c11237b427d825016165edcb6c742 100644
--- a/tests/scenarios/Authorities/AuthoritiesTest.php
+++ b/tests/scenarios/Authorities/AuthoritiesTest.php
@@ -485,9 +485,9 @@ class AuthoritiesBibliographicDynamicFacetsWithoutIndexSystemTest extends ModelT
                     'id_thesaurus' => 'MOTS',
                     'id_origine' => null,
                     'code' => 'MOTS',
-                    'rule_zone' => '619',
-                    'rule_label_field' => 'a',
-                    'rule_id_field' => '9']);
+                    'rule_list_zone' => ['619'],
+                    'rule_list_label_field' => ['a'],
+                    'rule_list_id_field' => ['9']]);
 
     $this->_thesauri = (new Class_Cosmogramme_Integration_Record_BibliographicDynamicFacets())
       ->thesauriOf((new Class_NoticeUnimarc())->setNotice(file_get_contents(__DIR__ . '/vagabond.mrc')),
@@ -548,9 +548,9 @@ class AuthoritiesBibliographicDynamicFacetsWithIndexSystemNotExistingTest extend
                     'id_thesaurus' => 'MOTS',
                     'id_origine' => null,
                     'code' => 'MOTS',
-                    'rule_zone' => '619',
-                    'rule_label_field' => 'a',
-                    'rule_id_field' => '9']);
+                    'rule_list_zone' => ['619','575'],
+                    'rule_list_label_field' => ['a','b'],
+                    'rule_list_id_field' => ['9','1']]);
 
     $attributs = [[Class_IntProfilDonnees::PROFILE_INDEX_SYSTEMS_FIELDS
                    => [['rule' => '',
@@ -574,6 +574,7 @@ class AuthoritiesBibliographicDynamicFacetsWithIndexSystemNotExistingTest extend
                    $this->fixture('Class_IntBib', ['id' => 3]));
 
     $this->_thesaurus = reset($thesauri);
+
     $this->_authority = Class_Notice::findFirstBy(['type' => Class_Notice::TYPE_AUTHORITY]);
   }
 
@@ -652,6 +653,7 @@ class AuthoritiesBibliographicDynamicFacetsWithIndexSystemNotExistingTest extend
 
 
 
+
 class AuthoritiesBibliographicDynamicFacetsWithIndexSystemAlreadyExistingTest extends ModelTestCase {
   protected
     $_thesaurus,
@@ -666,9 +668,9 @@ class AuthoritiesBibliographicDynamicFacetsWithIndexSystemAlreadyExistingTest ex
                     'id_thesaurus' => 'MOTS',
                     'id_origine' => null,
                     'code' => 'MOTS',
-                    'rule_zone' => '619',
-                    'rule_label_field' => 'a',
-                    'rule_id_field' => '9']);
+                    'rule_list_zone' => ['500', '619'],
+                    'rule_list_label_field' => ['b', 'a'],
+                    'rule_list_id_field' => ['', '9']]);
 
     $attributs = [[Class_IntProfilDonnees::PROFILE_INDEX_SYSTEMS_FIELDS
                    => [['rule' => '',
@@ -802,9 +804,9 @@ abstract class AuthoritiesFacetsWithIndexSystemTestCase extends ModelTestCase {
                     'id_thesaurus' => 'MOTS',
                     'id_origine' => null,
                     'code' => 'MOTS',
-                    'rule_zone' => '619',
-                    'rule_label_field' => 'a',
-                    'rule_id_field' => '9']);
+                    'rule_list_zone' => ['619'],
+                    'rule_list_label_field' => ['a'],
+                    'rule_list_id_field' => ['9']]);
   }
 
 
diff --git a/tests/scenarios/SearchResult/SearchResultTest.php b/tests/scenarios/SearchResult/SearchResultTest.php
index 4687e482260ea1a03dcb2cb0d46153f9718260b6..e5ea7c437801b20a101d7331a33ccf39dd6c7177 100644
--- a/tests/scenarios/SearchResult/SearchResultTest.php
+++ b/tests/scenarios/SearchResult/SearchResultTest.php
@@ -89,8 +89,7 @@ class SearchResultHeaderTest extends AbstractControllerTestCase {
   /** @test */
   public function searchModeWidgetShouldSelect() {
     $this->assertXPathContentContains('//form//select[@name="in_files"]//option[@selected][@value="0"]',
-                                      'Index seulement',
-                                      $this->_response->getBody());
+                                      'Index seulement');
   }
 }
 
@@ -259,8 +258,8 @@ class SearchResultWithDynamicFacetTest extends AbstractControllerTestCase {
                     'id_thesaurus' => 'DOCU',
                     'id_origine' => null,
                     'code' => 'DOCU',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 't']);
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['t']]);
 
     $this->fixture('Class_CodifThesaurus',
                    ['id' => 4,
@@ -269,8 +268,8 @@ class SearchResultWithDynamicFacetTest extends AbstractControllerTestCase {
                     'id_thesaurus' => 'DOCU0001',
                     'id_origine' => null,
                     'code' => 'DOCU',
-                    'rule_zone' => '995',
-                    'rule_label_field' => 't']);
+                    'rule_list_zone' => ['995'],
+                    'rule_list_label_field' => ['t']]);
   }
 
 
diff --git a/tests/scenarios/Templates/TemplatesSearchItemsTest.php b/tests/scenarios/Templates/TemplatesSearchItemsTest.php
index ef960f9828b59c46e7e83af71f289fb89cad6329..d6048df200b1a6683bb3b58cffda88d4937acbdd 100644
--- a/tests/scenarios/Templates/TemplatesSearchItemsTest.php
+++ b/tests/scenarios/Templates/TemplatesSearchItemsTest.php
@@ -207,8 +207,8 @@ class TemplatesSearchItemsNoticeAjaxResourcesActionTest extends TemplatesTestSea
                               'libelle_facette' => 'Public',
                               'code' => 'Public',
                               'id_thesaurus' => 'PUBL',
-                              'rule_zone' => '686',
-                              'rule_label_field' => 'a']);
+                              'rule_list_zone' => ['686'],
+                              'rule_list_label_field' => ['a']]);
 
     $i_like = $this->fixture(Class_CodifThesaurus::class,
                              ['id' => 2,
@@ -216,8 +216,8 @@ class TemplatesSearchItemsNoticeAjaxResourcesActionTest extends TemplatesTestSea
                               'libelle_facette' => 'I like',
                               'code' => 'I like',
                               'id_thesaurus' => 'ILIK',
-                              'rule_zone' => '995',
-                              'rule_label_field' => 'd']);
+                              'rule_list_zone' => ['995'],
+                              'rule_list_label_field' => ['d']]);
 
     $emplacements = $this->fixture(Class_CodifThesaurus::class,
                                    ['id' => 3,
@@ -225,8 +225,8 @@ class TemplatesSearchItemsNoticeAjaxResourcesActionTest extends TemplatesTestSea
                                     'libelle_facette' => 'Emplacement',
                                     'code' => 'Emplacement',
                                     'id_thesaurus' => 'EMPL',
-                                    'rule_zone' => '995',
-                                    'rule_label_field' => 'b']);
+                                    'rule_list_zone' => ['995'],
+                                    'rule_list_label_field' => ['b']]);
 
     $emplacements->getOrCreateChild('EMPL1', 'Chambre');
     $emplacements->getOrCreateChild('EMPL2', 'Salon');
diff --git a/tests/scenarios/Thesauri/ThesauriTest.php b/tests/scenarios/Thesauri/ThesauriTest.php
index 3a5b4799466be5b7bb8260572c2ec13298aeef61..e742748f4bc924da33b4900aeb37a64bc656158a 100644
--- a/tests/scenarios/Thesauri/ThesauriTest.php
+++ b/tests/scenarios/Thesauri/ThesauriTest.php
@@ -38,8 +38,8 @@ abstract class ThesauriTestCase extends Admin_AbstractControllerTestCase {
                                    'id_thesaurus' => 'DOCU',
                                    'id_origine' => null,
                                    'code' => 'DOCU',
-                                   'rule_zone' => '099',
-                                   'rule_label_field' => 't']);
+                                   'rule_list_zone' => ['099'],
+                                   'rule_list_label_field' => ['t']]);
 
     $this->_sifi = $this->fixture('Class_CodifThesaurus',
                                   ['id' => 4,
@@ -237,6 +237,6 @@ class ThesauriEditTest extends ThesauriTestCase {
   /** @test */
   public function thesauriShouldNotHaveBeenUpdated() {
     $this->postDispatch('/admin/thesauri/edit/id/3', ['rules' => 'brave']);
-    $this->assertEquals('099', Class_CodifThesaurus::find(3)->getRuleZone());
+    $this->assertSame(['099'], Class_CodifThesaurus::find(3)->getRuleListZone());
   }
 }
\ No newline at end of file