From 067c725cd42588cb6f3c7df73c3f80244277aeb1 Mon Sep 17 00:00:00 2001
From: Patrick Barroca <pbarroca@afi-sa.fr>
Date: Fri, 20 May 2022 15:41:54 +0200
Subject: [PATCH] hotline #149668 : article pseudo record phase optim

---
 VERSIONS_HOTLINE/149668                       |   1 +
 .../Integration/PhasePseudoRecordCms.php      |  80 ++++++++-
 .../Integration/PhasePseudoRecordCmsTest.php  | 166 ++++++++++++++++++
 .../Integration/PhasePseudoRecordTest.php     |  63 -------
 4 files changed, 244 insertions(+), 66 deletions(-)
 create mode 100644 VERSIONS_HOTLINE/149668
 create mode 100644 tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordCmsTest.php

diff --git a/VERSIONS_HOTLINE/149668 b/VERSIONS_HOTLINE/149668
new file mode 100644
index 00000000000..74fe1af5b68
--- /dev/null
+++ b/VERSIONS_HOTLINE/149668
@@ -0,0 +1 @@
+ - correctif #149668 : Intégrations : Amélioration des performance de la phase d'indexation des arcticles CMS Bokeh
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Integration/PhasePseudoRecordCms.php b/library/Class/Cosmogramme/Integration/PhasePseudoRecordCms.php
index 7daa79bdac5..84285c5eee2 100644
--- a/library/Class/Cosmogramme/Integration/PhasePseudoRecordCms.php
+++ b/library/Class/Cosmogramme/Integration/PhasePseudoRecordCms.php
@@ -20,15 +20,89 @@
  */
 
 
-class Class_Cosmogramme_Integration_PhasePseudoRecordCms extends Class_Cosmogramme_Integration_PhasePseudoRecord {
+class Class_Cosmogramme_Integration_PhasePseudoRecordCms
+  extends Class_Cosmogramme_Integration_PhasePseudoRecord {
   const MY_ID = 0.2;
 
   protected $_label = 'Pseudo-notices : CMS';
-  protected $_model_name = 'Class_Article';
+  protected $_model_name = Class_Article::class;
 
 
   /** @return array **/
   protected function _previousPhaseIds() {
     return [0.1];
   }
-}
\ No newline at end of file
+
+
+  public function isTimeOut() {
+    return false;
+  }
+
+
+  protected function _execute() {
+    $this->_unindexUnpublished()
+         ->_indexPublished()
+         ->_summarize();
+  }
+
+
+  protected function _unindexUnpublished() : self {
+    $ids = Zend_Registry::get('sql')
+      ->fetchAllByColumn('select n.id_notice '
+                         . $this->_articlesRecordsJoin()
+                         . ' where (a.debut is not null and date(a.debut) > date(now())) or (a.fin is not null and date(a.fin) < date(now()))');
+
+    if (!$ids) {
+      $this->_log->info($this->_('Aucun article à désindexer'));
+      return $this;
+    }
+
+    Class_Notice::basicDeleteBy(['id_notice' => $ids]);
+    Class_Exemplaire::basicDeleteBy(['id_notice' => $ids]);
+
+    $count = count($ids);
+
+    $this->_log->info($this->_plural($count,
+                                     'Aucun article à désindexer',
+                                     '1 article désindexé',
+                                     '%d articles désindexés',
+                                     $count));
+
+    return $this;
+  }
+
+
+  protected function _indexPublished() : self {
+    $published_select = 'select a.id_article ' . $this->_articlesRecordsJoin();
+
+    $sql = 'select id_article '
+      . 'from cms_article '
+      . 'where id_article not in ('. $published_select . ') '
+      . 'and ((debut is null or date(debut) <= date(now())) and (fin is null or date(fin) >= date(now()))) '
+      . 'and status='. Class_Article::STATUS_VALIDATED . ' and indexation=1 '
+      . 'order by id_article';
+
+    if ($ids = Zend_Registry::get('sql')->fetchAllByColumn($sql)) {
+      $count = count($ids);
+      $this->_log->info($this->_plural($count,
+                                       'Aucun article à indexer',
+                                       '1 article à indexer',
+                                       '%d articles à indexer',
+                                       $count));
+    }
+
+    foreach(array_chunk($ids, 100) as $page_ids) {
+      $this->_runPage(Class_Article::findAllBy(['id_article' => $page_ids]));
+      $this->_cleanMemory();
+    }
+
+    return $this;
+  }
+
+
+  protected function _articlesRecordsJoin() : string {
+    return 'from notices as n '
+      . 'inner join exemplaires as e on (n.id_notice=e.id_notice and n.type=1 and n.type_doc="' . Class_TypeDoc::ARTICLE . '") '
+      . 'inner join cms_article as a on a.id_article=e.id_origine';
+  }
+}
diff --git a/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordCmsTest.php b/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordCmsTest.php
new file mode 100644
index 00000000000..20386882e7a
--- /dev/null
+++ b/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordCmsTest.php
@@ -0,0 +1,166 @@
+<?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 PhasePseudoRecordCmsUnindexTest extends Class_Cosmogramme_Integration_PhaseTestCase {
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.1))
+      ->beCron();
+  }
+
+
+  public function setUp() {
+    parent::setUp();
+    Zend_Registry::set('sql',
+                       $this->mock()
+                       ->whenCalled('fetchAllByColumn')->answers([])
+
+                       ->whenCalled('fetchAllByColumn')
+                       ->with('select n.id_notice from notices as n inner join exemplaires as e on (n.id_notice=e.id_notice and n.type=1 and n.type_doc="8") inner join cms_article as a on a.id_article=e.id_origine where (a.debut is not null and date(a.debut) > date(now())) or (a.fin is not null and date(a.fin) < date(now()))')
+                       ->answers([12]));
+
+    $this->fixture(Class_Article::class,
+                   ['id' => 22199,
+                    'titre' => 'Testing article',
+                    'contenu' => 'Testing article',
+                    'status' => Class_Article::STATUS_VALIDATED,
+                    'indexation' => 1,
+                    'debut' => '2022-04-21',
+                    'fin' => '2022-05-19'
+                   ]);
+
+    $this->fixture(Class_Notice::class,
+                   ['id' => 12,
+                    'type' => Class_Notice::TYPE_BIBLIOGRAPHIC,
+                    'type_doc' => Class_TypeDoc::ARTICLE,
+                    'exemplaires' => [$this->fixture(Class_Exemplaire::class,
+                                                     ['id' => 12,
+                                                      'id_origine' => 22199])]]);
+
+    $this->_phase = $this->_buildPhase('PseudoRecordCms')
+                         ->setMemoryCleaner(function() {})
+                         ->run();
+  }
+
+
+  /** @test */
+  public function shouldNotBeError() {
+    $this->assertNotError();
+  }
+
+
+  /** @test */
+  public function record12ShouldBeDeleted() {
+    $this->assertNull(Class_Notice::findFirstBy([]));
+  }
+
+
+  /** @test */
+  public function item12ShouldBeDeleted() {
+    $this->assertNull(Class_Exemplaire::findFirstBy([]));
+  }
+
+
+  /** @test */
+  public function logShouldContains1ArticleDésindexé() {
+    $this->assertLogContains('1 article désindexé');
+  }
+
+
+  /** @test */
+  public function logShouldContainsAucuneNoticeATraiter() {
+    $this->assertLogContains('Aucune notice à traiter');
+  }
+}
+
+
+
+
+class PhasePseudoRecordCmsIndexTest extends Class_Cosmogramme_Integration_PhaseTestCase {
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.1))
+      ->beCron();
+  }
+
+
+  public function setUp() {
+    parent::setUp();
+    Zend_Registry::set('sql',
+                       $this->mock()
+                       ->whenCalled('fetchAllByColumn')->answers([])
+
+                       ->whenCalled('fetchAllByColumn')
+                       ->with('select id_article from cms_article where id_article not in (select a.id_article from notices as n inner join exemplaires as e on (n.id_notice=e.id_notice and n.type=1 and n.type_doc="8") inner join cms_article as a on a.id_article=e.id_origine) and ((debut is null or date(debut) <= date(now())) and (fin is null or date(fin) >= date(now()))) and status=3 and indexation=1 order by id_article')
+                       ->answers([22199]));
+
+    Class_Article::setTimeSource(new TimeSourceForTest('2022-04-30 14:50:49'));
+
+    $this->fixture(Class_Article::class,
+                   ['id' => 22199,
+                    'titre' => 'Testing article',
+                    'contenu' => 'Testing article',
+                    'status' => Class_Article::STATUS_VALIDATED,
+                    'indexation' => 1,
+                    'debut' => '2022-04-21',
+                    'fin' => '2022-05-19'
+                   ]);
+
+    $this->_phase = $this->_buildPhase('PseudoRecordCms')
+                         ->setMemoryCleaner(function() {})
+                         ->run();
+  }
+
+
+  public function tearDown() {
+    Class_Article::setTimeSource(null);
+    parent::tearDown();
+  }
+
+
+  /** @test */
+  public function shouldNotBeError() {
+    $this->assertNotError();
+  }
+
+
+  /** @test */
+  public function recordShouldBeCreated() {
+    $this->assertNotNull(Class_Notice::findFirstBy(['type_doc' => Class_TypeDoc::ARTICLE]));
+  }
+
+
+  /** @test */
+  public function itemShouldBeCreated() {
+    $this->assertNotNull(Class_Exemplaire::findFirstBy(['id_origine' => 22199]));
+  }
+
+
+  /** @test */
+  public function logShouldContainsAucunArticleADésindexer() {
+    $this->assertLogContains('Aucun article à désindexer');
+  }
+
+
+  /** @test */
+  public function logShouldContains1NoticeTraitee() {
+    $this->assertLogContains('1 notice(s) traitée(s)');
+  }
+}
diff --git a/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordTest.php b/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordTest.php
index c9f694ee7cf..b6827adc9b6 100644
--- a/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordTest.php
+++ b/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordTest.php
@@ -219,69 +219,6 @@ trait PhasePseudoRecordValidInteractiveCallback {
 }
 
 
-/**
- * CMS
- */
-
-abstract class PhasePseudoRecordCmsTestCase extends PhasePseudoRecordTestCase {
-  protected
-    $_phase_name = 'PseudoRecordCms',
-    $_phase_label = 'Pseudo-notices : CMS',
-    $_model_name = 'Class_Article',
-    $_model_id = 'id_article';
-
-
-  protected function _getModelAttribs($id) {
-    return array_merge(parent::_getModelAttribs($id),
-                       ['titre' => 'Article ' . $id,
-                        'contenu' => 'Content ' . $id]);
-  }
-}
-
-
-
-class PhasePseudoRecordCmsInvalidPreviousPhaseTest extends PhasePseudoRecordCmsTestCase {
-  use PhasePseudoRecordInvalidPreviousPhase;
-}
-
-
-
-class PhasePseudoRecordCmsValidCronTest extends PhasePseudoRecordCmsTestCase {
-  use PhasePseudoRecordValidCron;
-
-  protected function _getPreviousPhase() {
-    return (new Class_Cosmogramme_Integration_Phase(0.1))
-      ->setData('pointeur_reprise', 45)
-      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 5)
-      ->beCron();
-  }
-}
-
-
-
-class PhasePseudoRecordCmsValidInteractiveTimeoutTest
-  extends PhasePseudoRecordCmsTestCase {
-  use PhasePseudoRecordValidInteractiveTimeout;
-
-  protected function _getPreviousPhase() {
-    return (new Class_Cosmogramme_Integration_Phase(0.1));
-  }
-}
-
-
-
-class PhasePseudoRecordCmsValidInteractiveCallbackTest
-  extends PhasePseudoRecordCmsTestCase {
-  use PhasePseudoRecordValidInteractiveCallback;
-
-  protected function _getPreviousPhase() {
-    return (new Class_Cosmogramme_Integration_Phase(0.2))
-      ->beCallBack()
-      ->setData('nombre', 1)
-      ->setData('pointeur_reprise', 15)
-      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 6);
-  }
-}
 
 
 /**
-- 
GitLab