From c00e7f28d3e367a8c26d539686457c5dd4dba0e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?ANDRE=20s=C3=A9bastien?= <sandre@afi-sa.fr>
Date: Thu, 3 Feb 2022 15:32:03 +0100
Subject: [PATCH] dev #135273 : Import Subject with multiple $a on same 610
 line

---
 FEATURES/135273                               |  10 ++
 VERSIONS_WIP/135273                           |   1 +
 .../classes/classe_notice_archive_calice.php  |   2 +-
 .../classes/NoticeIntegrationSubjectTest.php  | 103 ++++++++++++++++++
 .../php/classes/unimarc_insep_subject.txt     |   1 +
 library/Class/Matiere/RuleField.php           |  43 ++++++++
 library/Class/Matiere/RuleMatter.php          |  57 ++++++++++
 library/Class/Matiere/RuleZone.php            |  88 +++++++++++++++
 library/Class/Matiere/Rules.php               |  98 +++++++++++++++++
 library/Class/NoticeUnimarc.php               |  23 +---
 10 files changed, 403 insertions(+), 23 deletions(-)
 create mode 100644 FEATURES/135273
 create mode 100644 VERSIONS_WIP/135273
 create mode 100644 cosmogramme/tests/php/classes/NoticeIntegrationSubjectTest.php
 create mode 100644 cosmogramme/tests/php/classes/unimarc_insep_subject.txt
 create mode 100644 library/Class/Matiere/RuleField.php
 create mode 100644 library/Class/Matiere/RuleMatter.php
 create mode 100644 library/Class/Matiere/RuleZone.php
 create mode 100644 library/Class/Matiere/Rules.php

diff --git a/FEATURES/135273 b/FEATURES/135273
new file mode 100644
index 00000000000..09cb9be8d32
--- /dev/null
+++ b/FEATURES/135273
@@ -0,0 +1,10 @@
+        '135273' =>
+            ['Label' => $this->_('Import des Matières, avoir la possibilité de gérer plusieurs $a sur une même ligne de 610'),
+             'Desc' => '',
+             'Image' => '',
+             'Video' => '',
+             'Category' => $this->_('Cosmogramme'),
+             'Right' => function($feature_description, $user) {return true;},
+             'Wiki' => 'https://wiki.bokeh-library-portal.org/index.php?title=Facette_Matiere_Sujet',
+             'Test' => '',
+             'Date' => '2022-02-03'],
\ No newline at end of file
diff --git a/VERSIONS_WIP/135273 b/VERSIONS_WIP/135273
new file mode 100644
index 00000000000..137642bcd02
--- /dev/null
+++ b/VERSIONS_WIP/135273
@@ -0,0 +1 @@
+ - fonctionnalité #135273 : Cosmogramme : Import des Matières, avoir la possibilité de gérer plusieurs $a sur une même ligne de 610
\ No newline at end of file
diff --git a/cosmogramme/php/classes/classe_notice_archive_calice.php b/cosmogramme/php/classes/classe_notice_archive_calice.php
index 4d811a9eee0..51d3538c8d9 100644
--- a/cosmogramme/php/classes/classe_notice_archive_calice.php
+++ b/cosmogramme/php/classes/classe_notice_archive_calice.php
@@ -327,4 +327,4 @@ class notice_archive_calice
 		return $this->erreur;
 	}
 }
-?>
\ No newline at end of file
+?>
diff --git a/cosmogramme/tests/php/classes/NoticeIntegrationSubjectTest.php b/cosmogramme/tests/php/classes/NoticeIntegrationSubjectTest.php
new file mode 100644
index 00000000000..dc6181056ce
--- /dev/null
+++ b/cosmogramme/tests/php/classes/NoticeIntegrationSubjectTest.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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
+ */
+
+require_once 'NoticeIntegrationTest.php';
+
+class NoticeIntegrationSubjectTest extends NoticeIntegrationTestCase {
+
+  protected $_storm_default_to_volatile = true;
+
+  public function setUp() {
+    parent::setUp();
+
+    Class_CosmoVar::newInstanceWithId('unimarc_zone_matiere',
+                                      ['valeur' => '610aejxyz']);
+
+    /**
+     * 2 lines with label 610 :
+     * 610    $k Zone $j Annees $a Technique $a Initiation $y 2020 $a Sport $w Rien
+     * 610    $a Nautique $a Paddle
+     */
+    $this->loadNotice('unimarc_insep_subject');
+  }
+
+
+  public function getProfilDonnees() {
+    return Class_IntProfilDonnees::forKoha()
+      ->setIdProfil(110)
+      ->getRawAttributes();
+  }
+
+
+  /** @test */
+  public function noticeIndexMatieresShouldBeAllPhoneticLabel() {
+    $this->assertEquals('ANNEES AN TECHNIQUE TEKNIK 2020 INITIATION INITIASION SPORT SPOR NAUTIQUE NOTIK PADDLE PADL',
+                        Class_Notice::find(1)->getMatieres());
+  }
+
+
+  /** @test */
+  public function noticeFacettesShouldContainsFacetsSubjectM1M2M3M4M5() {
+    $this->assertContains('T1 D94438 A1 M1 M2 M3 M4 M5 Lfre',
+                          Class_Notice::find(1)->getFacettes());
+  }
+
+
+  /** @test */
+  public function fiveCodifMatiereShouldBeCreated() {
+    $this->assertEquals(5, Class_CodifMatiere::count());
+  }
+
+
+  /** @test */
+  public function codifMatiereOneShouldBeAnneesTechnique2020() {
+    $this->assertEquals('Annees : Technique : 2020',
+                        Class_CodifMatiere::find(1)->getLibelle());
+  }
+
+
+  /** @test */
+  public function codifMatiereTwoShouldBeAnneesInitiation2020() {
+    $this->assertEquals('Annees : Initiation : 2020',
+                        Class_CodifMatiere::find(2)->getLibelle());
+  }
+
+
+  /** @test */
+  public function codifMatiereThreeShouldBeAnnees2020Sport() {
+    $this->assertEquals('Annees : 2020 : Sport',
+                        Class_CodifMatiere::find(3)->getLibelle());
+  }
+
+
+  /** @test */
+  public function codifMatiereForShouldBeNautique() {
+    $this->assertEquals('Nautique',
+                        Class_CodifMatiere::find(4)->getLibelle());
+  }
+
+
+  /** @test */
+  public function codifMatiereFiveShouldBePaddle() {
+    $this->assertEquals('Paddle',
+                        Class_CodifMatiere::find(5)->getLibelle());
+  }
+}
diff --git a/cosmogramme/tests/php/classes/unimarc_insep_subject.txt b/cosmogramme/tests/php/classes/unimarc_insep_subject.txt
new file mode 100644
index 00000000000..21d7dcfa1c1
--- /dev/null
+++ b/cosmogramme/tests/php/classes/unimarc_insep_subject.txt
@@ -0,0 +1 @@
+01411cam0 22003972  450 00100110000000500170001101000180002810000410004610100080008710200130009510500180010820001070012621000310023321500240026422500360028832000250032461000590034961000210040867600190042969000130044869000120046169200490047369200460052269200500056870200270061870200290064580100130067480100240068780100240071190100200073590100170075590200310077295100160080399500970081999500970091601-000364220140507162502.0  a2-7158-0389-3  a20081211d2008    m  y0frey0103    ba  afre  aXXXXb??  aa       00|||1 aArchives d'Alsacef[textes et documents choisis et prÂesentÂes par] Jacques BorgÂe et Nicolas Viasnoff  31821aPariscBallandd1982  a233 p.cill.d29 cm2 32291aArchives de la Francev8.  aBibliogr. p. 229-231  kZonejAnneesaTechniqueaInitiationy2020aSportwRien  aNautiqueaPaddle  3122620a944.38  3874a944  3772aFD  36aDocumentaire2CS3NType document Multilis  33aAlsatique2CS3NType document Multilis  32546aAlsace, ca 1870-19142CS4NThÁeme libre  315541aBorgÂebJacques  315542aViasnoffbNicolas 1bBMCOLMAR 2aFRb68066c20140507 3aFRb68066c20141120  36aDocumentaire  33aAlsatique  32546aAlsace, ca 1870-1914  aDKb ** c1  a68066f30179001905666kA 7779opqarauyBibliothÁeque des DominicainszSalle des Catalogues  a68066f30179001905674kA 7757opqarauyBibliothÁeque des DominicainszSalle des Catalogues
\ No newline at end of file
diff --git a/library/Class/Matiere/RuleField.php b/library/Class/Matiere/RuleField.php
new file mode 100644
index 00000000000..028865db8b3
--- /dev/null
+++ b/library/Class/Matiere/RuleField.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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_Matiere_RuleField {
+
+  protected
+    $_code,
+    $_label;
+
+  public function __construct(string $code, string $label) {
+    $this->_code = $code;
+    $this->_label = $label;
+  }
+
+
+  public function getCode() : string {
+    return $this->_code;
+  }
+
+
+  public function getLabel() : string {
+    return $this->_label;
+  }
+}
diff --git a/library/Class/Matiere/RuleMatter.php b/library/Class/Matiere/RuleMatter.php
new file mode 100644
index 00000000000..98b2216e405
--- /dev/null
+++ b/library/Class/Matiere/RuleMatter.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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_Matiere_RuleMatter {
+
+  protected $_rules_fields;
+
+  public function __construct(?Storm_Collection $rules_fields = null) {
+    $this->_rules_fields = new Storm_Collection;
+    if ($rules_fields)
+      $this->_rules_fields->addAll($rules_fields);
+  }
+
+
+  public function addField(Class_Matiere_RuleField $rule_field) : self {
+    $this->_rules_fields->add($rule_field);
+    return $this;
+  }
+
+
+  public function existMultiple() : bool {
+    return null !== $this->_rules_fields
+      ->detect(fn($field) => 'a' === $field->getCode());
+  }
+
+
+  public function getCommonsFields() : Storm_Collection {
+    return $this->_rules_fields
+      ->select(fn($field) => 'a' !== $field->getCode());
+  }
+
+
+  public function getLabel() : string {
+    return implode(' : ', $this->_rules_fields
+                   ->collect(fn($field) => $field->getLabel())
+                   ->getArrayCopy());
+  }
+}
diff --git a/library/Class/Matiere/RuleZone.php b/library/Class/Matiere/RuleZone.php
new file mode 100644
index 00000000000..1ca0f55764c
--- /dev/null
+++ b/library/Class/Matiere/RuleZone.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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_Matiere_RuleZone {
+
+  protected
+    $_label_unimarc,
+    $_rules_matters,
+    $_commons_fields;
+
+  public function __construct(string $label_unimarc) {
+    $this->_label_unimarc = $label_unimarc;
+  }
+
+
+  public function addField(Class_Matiere_RuleField $rule_field) : self {
+    if (!$this->_rules_matters) {
+      $this->_rules_matters = new Storm_Collection;
+      $rule_matter = (new Class_Matiere_RuleMatter)
+        ->addField($rule_field);
+      $this->_rules_matters->add($rule_matter);
+      return $this;
+    }
+
+    if ($this->_isMultipleField($rule_field)) {
+      $rule_matter = (new Class_Matiere_RuleMatter($this->_getCommonsFields()))
+        ->addField($rule_field);
+      $this->_rules_matters->add($rule_matter);
+      return $this;
+    }
+
+    $this->_rules_matters->eachDo(fn($matter) => $matter->addField($rule_field));
+    $this->_addInCommonsFields($rule_field);
+    return $this;
+  }
+
+
+  public function getLabels() : array {
+    return $this->_rules_matters
+      ->collect(fn($rule_matter) => $rule_matter->getLabel())
+      ->getArrayCopy();
+  }
+
+
+  protected function _isMultipleField(Class_Matiere_RuleField $rule_field) : bool {
+    if ('610a' !== ($this->_label_unimarc . $rule_field->getCode()))
+      return false;
+
+    return $this->_rules_matters->count() > 1
+      || $this->_rules_matters->first()->existMultiple();
+  }
+
+
+  protected function _getCommonsFields() : Storm_Collection {
+    return $this->_commons_fields
+      ? $this->_commons_fields
+      : ($this->_commons_fields = $this->_rules_matters
+         ->first()
+         ->getCommonsFields());
+  }
+
+
+  protected function _addInCommonsFields($field) : self {
+    if ($this->_commons_fields)
+      $this->_commons_fields->add($field);
+
+    return $this;
+  }
+}
diff --git a/library/Class/Matiere/Rules.php b/library/Class/Matiere/Rules.php
new file mode 100644
index 00000000000..3e3c2456aae
--- /dev/null
+++ b/library/Class/Matiere/Rules.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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_Matiere_Rules {
+
+  protected
+    $_notice_unimarc,
+    $_rules_zones;
+
+  public function __construct(Class_NoticeUnimarc $notice_unimarc) {
+    $this->_notice_unimarc = $notice_unimarc;
+    $this->_rules_zones = new Storm_Collection;
+    $this->_init();
+  }
+
+
+  public function getAllLabels() : array {
+    return $this->_rules_zones
+      ->injectInto([],
+                   fn($labels, $rule_zone) => array_merge($labels,
+                                                          $rule_zone->getLabels()));
+  }
+
+
+  protected function _init() : self {
+    $zones = explode(';', Class_CosmoVar::get('unimarc_zone_matiere'));
+    foreach ($zones as $zone)
+      $this->_extractByZone(trim($zone));
+
+    return $this;
+  }
+
+
+  /**
+   * @param $zone string 600abcxj
+   */
+  protected function _extractByZone(string $zone) : self {
+    $label_unimarc = strLeft($zone, 3);
+    $codes = strMid($zone, 3, 10);
+
+    $subfields = $this->_notice_unimarc->get_subfield($label_unimarc);
+    foreach ($subfields as $subfield)
+      $this->_addFields($label_unimarc, $codes, $subfield);
+
+    return $this;
+  }
+
+
+  protected function _addFields(string $label_unimarc,
+                                string $codes,
+                                string $subfield) : self {
+    if (!$fields = $this->_prepareFields($subfield, $codes))
+      return $this;
+
+    $rule_zone = new Class_Matiere_RuleZone($label_unimarc);
+    $this->_rules_zones->add($rule_zone);
+
+    foreach ($fields as $field)
+      $rule_zone->addField($field);
+
+    return $this;
+  }
+
+
+  protected function _prepareFields(string $subfield, string $codes) : array {
+    $fields = $this->_notice_unimarc->decoupe_bloc_champ($subfield);
+    $fields = array_map(function ($field) use ($codes) {
+      $code = trim($field['code'] ?? '');
+      $label = trim($field['valeur'] ?? '');
+
+      return $code && $label && (false !== strpos($codes, $code))
+        ? new Class_Matiere_RuleField($code, $label)
+        : null;
+    },
+                        $fields);
+
+    return array_filter($fields);
+  }
+}
diff --git a/library/Class/NoticeUnimarc.php b/library/Class/NoticeUnimarc.php
index b891d213c12..35b9afc4a91 100644
--- a/library/Class/NoticeUnimarc.php
+++ b/library/Class/NoticeUnimarc.php
@@ -272,28 +272,7 @@ class Class_NoticeUnimarc {
 
 
   public function getMatieresLabels() {
-    $matiere = [];
-    $zones = Class_CosmoVar::get('unimarc_zone_matiere');
-    $zones = explode(';', trim($zones));
-    foreach ($zones as $elem) {
-      $data = $this->get_subfield(strLeft($elem, 3));
-      $champs = strMid($elem, 3, 10);
-      foreach ($data as $items) {
-        $sous_champs = $this->decoupe_bloc_champ($items);
-        $mot = '';
-        foreach ($sous_champs as $item) {
-          if ($item['code'] &&
-              strpos($champs, $item['code']) !== false) {
-            if ($mot)
-              $mot.= ' : ';
-            $mot .= $item['valeur'];
-          }
-        }
-        $matiere[] = trim($mot);
-      }
-    }
-
-    return $matiere;
+    return (new Class_Matiere_Rules($this))->getAllLabels();
   }
 
 
-- 
GitLab