From 029f2a7644bc547355a4a8b9241e92d23f0df517 Mon Sep 17 00:00:00 2001
From: Laurent Laffont <llaffont@afi-sa.fr>
Date: Mon, 10 May 2021 17:56:52 +0200
Subject: [PATCH] dev #134950 Performances : write updated record and items
 only if needed

---
 VERSIONS_HOTLINE/134950                       |  1 +
 .../opac/controllers/AbonneController.php     |  4 --
 .../opac/controllers/NoticeajaxController.php |  8 +--
 library/Class/Exemplaire.php                  | 21 ++++--
 library/Class/Notice.php                      | 44 +-----------
 library/Class/Notice/Facettes.php             | 71 ++++++++++++++++++-
 .../Controller/Action/Helper/ViewRenderer.php |  5 ++
 .../ZendAfi/Controller/Plugin/XHProfile.php   |  3 +
 library/startup.php                           |  6 +-
 .../Chili/Library/Wrapper/Record.php          |  4 +-
 .../Intonation/Library/Record/Items.php       | 16 +----
 .../controllers/NoticeAjaxControllerTest.php  |  2 +
 .../Class/WebService/SIGB/CdScriptTest.php    |  4 +-
 13 files changed, 111 insertions(+), 78 deletions(-)
 create mode 100644 VERSIONS_HOTLINE/134950

diff --git a/VERSIONS_HOTLINE/134950 b/VERSIONS_HOTLINE/134950
new file mode 100644
index 00000000000..4cd65981422
--- /dev/null
+++ b/VERSIONS_HOTLINE/134950
@@ -0,0 +1 @@
+ - ticket #134950 : Amélioration des performances : diminution du nombre de requêtes vers forge.afi-sa.fr / diminution des requêtes de mise à jour des notices et exemplaires
\ No newline at end of file
diff --git a/application/modules/opac/controllers/AbonneController.php b/application/modules/opac/controllers/AbonneController.php
index 40e619e0c8e..64d2ad58463 100644
--- a/application/modules/opac/controllers/AbonneController.php
+++ b/application/modules/opac/controllers/AbonneController.php
@@ -1533,8 +1533,6 @@ class AbonneController extends ZendAfi_Controller_Action {
 
 
   public function reserverAction() {
-    session_write_close();
-
     $this->view->titre = $this->_('Réserver un document');
 
     if (!$record = Class_Notice::find($this->_getParam('record_id', 0)))
@@ -1557,8 +1555,6 @@ class AbonneController extends ZendAfi_Controller_Action {
     $items = (new Class_Profil_ItemsFilter())->select(Class_Profil::getCurrentProfil(), $items);
 
     $this->view->items = (new Class_CommSigb())->getDispoExemplaires($items);
-
-    $record->updateFacetsFromExemplaires();
   }
 
 
diff --git a/application/modules/opac/controllers/NoticeajaxController.php b/application/modules/opac/controllers/NoticeajaxController.php
index f071418abca..808576747fc 100644
--- a/application/modules/opac/controllers/NoticeajaxController.php
+++ b/application/modules/opac/controllers/NoticeajaxController.php
@@ -100,12 +100,10 @@ class NoticeAjaxController extends ZendAfi_Controller_Action {
     $exemplaires = $this->_loadExemplaire(["id_notice" => $notice_ids]);
 
     foreach($exemplaires as $exemplaire)
-      $exemplaire->updateAvailabilityAndLocationFromSIGB()
-                 ->save();
+      $exemplaire->updateAvailabilityAndLocationFromSIGBAndSaveIfNeeded();
 
     foreach(Class_Notice::findAllBy(['id_notice' => $notice_ids]) as $notice)
-      $notice->updateFacetsFromExemplaires()
-             ->save();
+      (new Class_Notice_Facettes($notice))->updateFacetsFromExemplairesAndSaveIfNeeded();
 
     $exemplaires = (new Class_CommSigb())->getDispoExemplaires($exemplaires);
 
@@ -708,4 +706,4 @@ class NoticeAjaxController extends ZendAfi_Controller_Action {
     $this->_helper->getHelper('HTMLAjaxResponse')
                   ->htmlAjaxResponseWithScript($content);
   }
-}
\ No newline at end of file
+}
diff --git a/library/Class/Exemplaire.php b/library/Class/Exemplaire.php
index 8fc0a97f611..9a9df0197a8 100644
--- a/library/Class/Exemplaire.php
+++ b/library/Class/Exemplaire.php
@@ -316,17 +316,28 @@ class Class_Exemplaire extends Storm_Model_Abstract {
   }
 
 
-  public function updateAvailabilityAndLocationFromSIGB() {
+  public function updateAvailabilityAndLocationFromSIGBAndSaveIfNeeded() {
     if (!$sigb_exemplaire = $this->getSigbExemplaire())
       return $this;
 
     if (!$sigb_exemplaire->isValid())
       return $this;
 
-    $this->setAnnexe($this->getCodeAnnexe());
-    return $this
-      ->setUrlForCurrentUser($sigb_exemplaire->getUrlForCurrentUser())
-      ->setIsAvailable($sigb_exemplaire->isDisponible());
+    $this->setUrlForCurrentUser($sigb_exemplaire->getUrlForCurrentUser());
+
+    $new_annexe = $this->getCodeAnnexe();
+    $new_availability = $sigb_exemplaire->isDisponible();
+
+    if (($new_annexe == $this->getAnnexe())
+        &&
+        ($new_availability  == $this->getIsAvailable()))
+      return $this;
+
+    $this
+      ->setAnnexe($new_annexe)
+      ->setIsAvailable($new_availability)
+      ->save();
+    return $this;
   }
 
 
diff --git a/library/Class/Notice.php b/library/Class/Notice.php
index d8d27dbad73..b36301fea9f 100644
--- a/library/Class/Notice.php
+++ b/library/Class/Notice.php
@@ -1824,49 +1824,9 @@ class Class_Notice extends Storm_Model_Abstract {
   }
 
 
-  protected function _fetchItemsToInjectInFacets() {
-    if ($this->isPeriodiqueArticle() && ($linked_record = $this->getLinkedSerialRecord()))
-      return $linked_record->getExemplaires();
-
-    if (!$this->isPeriodiqueTitle())
-      return $this->getExemplaires();
-
-    $clef_chapeau = Class_Indexation::getInstance()->codeAlphaTitre($this->getTitrePrincipal());
-    $records = $this->getLoader()->getAllNoticesByClefChapeau($clef_chapeau);
-    $record_ids = (new Storm_Model_Collection($records))->collect('id');
-
-    if ($record_ids->isEmpty())
-      return [];
-
-    return Class_Exemplaire::findAllBy(['id_notice' => $record_ids->getArrayCopy()]);
-  }
-
-
   public function updateFacetsFromExemplaires() {
-    $facets = Class_Notice_Facette::fromStringWithoutItemFacets($this->getFacettes());
-    $facets = array_map(function($facet) { return $facet->getCle(); },
-                        $facets);
-
-    $facets[] = Class_CodifTypeDoc::CODE_FACETTE . $this->getTypeDoc();
-
-    $is_novelty = false;
-    $date_nouveaute = '';
-    foreach($this->_fetchItemsToInjectInFacets() as $exemplaire) {
-      $facets = array_merge($facets, $exemplaire->getFacets());
-
-      $date_nouveaute = ($exemplaire->getDateNouveaute() > $date_nouveaute)
-        ? $exemplaire->getDateNouveaute()
-        : $date_nouveaute;
-
-      $is_novelty = $is_novelty || $exemplaire->isNouveaute();
-    }
-
-    if ($novelty_thesaurus = Class_CodifThesaurus::recordNoveltyFor($is_novelty))
-      $facets[] = $novelty_thesaurus->getFacetCode();
-
-    return $this
-      ->setFacettes(array_unique($facets))
-      ->setDateCreation($date_nouveaute ? ($date_nouveaute . ' 00:00:00') : null);
+    (new Class_Notice_Facettes($this))->updateFacetsFromExemplaires();
+    return $this;
   }
 
 
diff --git a/library/Class/Notice/Facettes.php b/library/Class/Notice/Facettes.php
index ae7ef602c2f..eb9ea2a6b30 100644
--- a/library/Class/Notice/Facettes.php
+++ b/library/Class/Notice/Facettes.php
@@ -21,6 +21,8 @@
 
 
 class Class_Notice_Facettes {
+  protected $_record;
+
   public static function mergeFacettes($old_facettes, $facettes) {
     return implode(' ', array_filter(array_unique(array_merge(explode(' ', $old_facettes), explode(' ', $facettes)))));
   }
@@ -29,5 +31,72 @@ class Class_Notice_Facettes {
   public static function removeFacettes($old_facettes, $facettes) {
     return implode(' ', array_filter(array_diff(explode(' ', $old_facettes), explode(' ', $facettes))));
   }
+
+
+  public function __construct($record) {
+    $this->_record = $record;
+  }
+
+
+  public function updateFacetsFromExemplaires() {
+    $facets = Class_Notice_Facette::fromStringWithoutItemFacets($this->_record->getFacettes());
+    $facets = array_map(function($facet) { return $facet->getCle(); },
+                        $facets);
+
+    $facets[] = Class_CodifTypeDoc::CODE_FACETTE . $this->_record->getTypeDoc();
+
+    $is_novelty = false;
+    $date_nouveaute = '';
+    foreach($this->_fetchItemsToInjectInFacets() as $exemplaire) {
+      $facets = array_merge($facets, $exemplaire->getFacets());
+
+      $date_nouveaute = ($exemplaire->getDateNouveaute() > $date_nouveaute)
+        ? $exemplaire->getDateNouveaute()
+        : $date_nouveaute;
+
+      $is_novelty = $is_novelty || $exemplaire->isNouveaute();
+    }
+
+    if ($novelty_thesaurus = Class_CodifThesaurus::recordNoveltyFor($is_novelty))
+      $facets[] = $novelty_thesaurus->getFacetCode();
+
+    return $this->_record
+      ->setFacettes(array_unique($facets))
+      ->setDateCreation($date_nouveaute ? ($date_nouveaute . ' 00:00:00') : null);
+  }
+
+
+  public function updateFacetsFromExemplairesAndSaveIfNeeded() {
+    $facets_before = $this->_record->getFacetCodes();
+    $creation_before = $this->_record->getDateCreation();
+    $this->updateFacetsFromExemplaires();
+
+    if (($facets_before == $this->_record->getFacetCodes())
+        &&
+        ($creation_before == $this->_record->getDateCreation()))
+      return $this;
+
+    $this->_record->save();
+    return $this;
+  }
+
+
+  protected function _fetchItemsToInjectInFacets() {
+    if ($this->_record->isPeriodiqueArticle() && ($linked_record = $this->_record->getLinkedSerialRecord()))
+      return $linked_record->getExemplaires();
+
+    if (!$this->_record->isPeriodiqueTitle())
+      return $this->_record->getExemplaires();
+
+    $clef_chapeau = Class_Indexation::getInstance()->codeAlphaTitre($this->_record->getTitrePrincipal());
+    $records = Class_Notice::getAllNoticesByClefChapeau($clef_chapeau);
+    $record_ids = (new Storm_Model_Collection($records))->collect('id');
+
+    if ($record_ids->isEmpty())
+      return [];
+
+    return Class_Exemplaire::findAllBy(['id_notice' => $record_ids->getArrayCopy()]);
+  }
+
 }
-?>
\ No newline at end of file
+?>
diff --git a/library/ZendAfi/Controller/Action/Helper/ViewRenderer.php b/library/ZendAfi/Controller/Action/Helper/ViewRenderer.php
index 9dce5cfc797..0bec9b470e4 100644
--- a/library/ZendAfi/Controller/Action/Helper/ViewRenderer.php
+++ b/library/ZendAfi/Controller/Action/Helper/ViewRenderer.php
@@ -54,9 +54,14 @@ class ZendAfi_Controller_Action_Helper_ViewRenderer extends Zend_Controller_Acti
 
     $this->view->_current_module = $this->getRequest()->getParam("current_module");
 
+
+    if (!Class_Template::current()->isLegacy())
+      return;
+
     $template = isset($this->view->_current_module["preferences"]["boite"])
       ? $this->view->_current_module["preferences"]["boite"]
       : null;
+
     $this->view->initBoite($template);
   }
 
diff --git a/library/ZendAfi/Controller/Plugin/XHProfile.php b/library/ZendAfi/Controller/Plugin/XHProfile.php
index 8b8ee018b74..0c8a2a04de1 100644
--- a/library/ZendAfi/Controller/Plugin/XHProfile.php
+++ b/library/ZendAfi/Controller/Plugin/XHProfile.php
@@ -45,6 +45,8 @@ class ZendAfi_Controller_Plugin_XHProfile extends Zend_Controller_Plugin_Abstrac
                             .appendTo(\'body .menu_admin_front .dev_tools\')');
 
     $this->_enabled = true;
+
+    Zend_Controller_Action_HelperBroker::getStaticHelper('redirector')->setExit(false);
     xhprof_enable();
   }
 
@@ -60,6 +62,7 @@ class ZendAfi_Controller_Plugin_XHProfile extends Zend_Controller_Plugin_Abstrac
     $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_testing");
 
     $this->_response
+      ->setHeader('X-XHPROF-RUN', $run_id)
       ->setRedirect(BASE_URL."/xhprof/xhprof_html/index.php?run={$run_id}&source=xhprof_testing\n")
       ->clearBody();
   }
diff --git a/library/startup.php b/library/startup.php
index 9fbaaf932fd..8c3d8977396 100644
--- a/library/startup.php
+++ b/library/startup.php
@@ -136,10 +136,10 @@ class Bokeh_Engine {
     defineConstant('URL_CAPTCHA', BASE_URL . '/temp/');
     defineConstant('PATH_CAPTCHA', PATH_TEMP);
     defineConstant('CACHE_LIFETIME', 3600);
+    defineConstant('CACHE_ENABLE', true);
     defineConstant('MEMCACHED_ENABLE', false);
     defineConstant('MEMCACHED_HOST', 'localhost');
     defineConstant('MEMCACHED_PORT', '11211');
-
     defineConstant('IMAGE_MAGICK_PATH', 'convert');
     defineConstant('THUMBNAIL_FIT_WIDTH_HEIGHT', '500');
 
@@ -171,7 +171,7 @@ class Bokeh_Engine {
   public function setupCache() {
     $frontendOptions = ['lifetime' => CACHE_LIFETIME, // durée du cache: 1h
                         'automatic_serialization' => false,
-                        'caching' => true];
+                        'caching' => CACHE_ENABLE];
 
     $use_memcached = (MEMCACHED_ENABLE === true);
     $backendOptions = $use_memcached
@@ -421,4 +421,4 @@ function setupOpac() {
   return (new Bokeh_Engine())
     ->powerOn()
     ->getFrontController();
-}
\ No newline at end of file
+}
diff --git a/library/templates/Chili/Library/Wrapper/Record.php b/library/templates/Chili/Library/Wrapper/Record.php
index 3b20172f2d7..5583ca30669 100644
--- a/library/templates/Chili/Library/Wrapper/Record.php
+++ b/library/templates/Chili/Library/Wrapper/Record.php
@@ -59,8 +59,8 @@ class Chili_Library_Wrapper_Record extends Intonation_Library_View_Wrapper_Recor
 
 
   protected function _addHoldLink($actions) {
-      $actions [] = (new Intonation_Library_Record($this->_model))
-        ->getFirstItemHoldLink($this->_view);
+    $actions [] = (new Intonation_Library_Record($this->_model))
+      ->getFirstItemHoldLink($this->_view);
 
     return $actions;
   }
diff --git a/library/templates/Intonation/Library/Record/Items.php b/library/templates/Intonation/Library/Record/Items.php
index f04cc34a74c..f47d21baf9e 100644
--- a/library/templates/Intonation/Library/Record/Items.php
+++ b/library/templates/Intonation/Library/Record/Items.php
@@ -39,10 +39,8 @@ class Intonation_Library_Record_Items {
 
 
   public function findAll() {
-    if (!$this->_items) {
+    if (!$this->_items)
       $this->_items = $this->_findItems();
-      $this->_updateRecordsFacetsFromItems();
-    }
 
     return $this->_items;
   }
@@ -51,22 +49,12 @@ class Intonation_Library_Record_Items {
   protected function _getItemsFromSIGB($items) {
     foreach($items as $item)
       $item
-      ->updateAvailabilityAndLocationFromSIGB()
-      ->save();
+      ->updateAvailabilityAndLocationFromSIGBAndSaveIfNeeded();
 
     return (new Class_CommSigb())->getDispoExemplaires($items);
   }
 
 
-  protected function _updateRecordsFacetsFromItems() {
-    foreach($this->_records as $record)
-      $record
-      ->updateFacetsFromExemplaires()
-      ->save();
-    return $this;
-  }
-
-
   protected function _getRecordIds() {
     return array_map(function($record)
                      {
diff --git a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
index 3dcac82d991..09f176d8cda 100644
--- a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
+++ b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
@@ -832,9 +832,11 @@ class NoticeAjaxControllerExemplairesWithOtherAnnexTestCase extends AbstractCont
 
   }
 
+
   /** @test */
   public function facetsShouldBeUpdatedWithAnnex21() {
     $this->dispatch('noticeajax/exemplaires/id/123');
+    Class_Notice::clearCache();
     $this->assertEquals('D78092 A3029 A9751 A117014 A117015 M37414 G464 HNNNN0002 HNANA0002 T0 B6 SA9 Eemplacement de test Y21 V6 HNRNR0001',
                         Class_notice::find(123)->getFacettes());
   }
diff --git a/tests/library/Class/WebService/SIGB/CdScriptTest.php b/tests/library/Class/WebService/SIGB/CdScriptTest.php
index 014575b65cf..fec9d9f6ed5 100644
--- a/tests/library/Class/WebService/SIGB/CdScriptTest.php
+++ b/tests/library/Class/WebService/SIGB/CdScriptTest.php
@@ -111,9 +111,9 @@ class CdScriptServiceTest extends CdScriptTestCase {
 
 
   /** @test */
-  public function onUpdateAvailabilityFromSIGBShouldItemShouldUpdateExternalUrlWithJumel() {
+  public function onUpdateAvailabilityFromSIGBItemShouldUpdateExternalUrlWithJumel() {
     $this->assertContains('jumel39',
-                          $this->_le_kiosque->updateAvailabilityAndLocationFromSIGB()->getExternalUrl());
+                          $this->_le_kiosque->updateAvailabilityAndLocationFromSIGBAndSaveIfNeeded()->getExternalUrl());
   }
 
 
-- 
GitLab