From 0e4d4ed853f5948c486d0daf31e156ff393aa8ea Mon Sep 17 00:00:00 2001
From: gloas <gloas@afi-sa.fr>
Date: Thu, 14 Feb 2019 16:42:05 +0100
Subject: [PATCH] hotline #86808 improve album categories with huge number of
 items deletion

---
 cosmogramme/VERSIONS_HOTLINE/86808            |  2 ++
 library/Class/AlbumCategorie.php              | 10 ++++++
 library/Class/AlbumCategorie/Remover.php      | 33 +++++++++++++++++
 .../Controller/Plugin/Manager/Album.php       |  9 +++--
 scripts/delete_album_category.php             | 16 +++++++++
 .../admin/controllers/AlbumControllerTest.php | 36 ++++++++++++++-----
 6 files changed, 95 insertions(+), 11 deletions(-)
 create mode 100644 cosmogramme/VERSIONS_HOTLINE/86808
 create mode 100644 library/Class/AlbumCategorie/Remover.php
 create mode 100644 scripts/delete_album_category.php

diff --git a/cosmogramme/VERSIONS_HOTLINE/86808 b/cosmogramme/VERSIONS_HOTLINE/86808
new file mode 100644
index 00000000000..c35ebc844a4
--- /dev/null
+++ b/cosmogramme/VERSIONS_HOTLINE/86808
@@ -0,0 +1,2 @@
+ - ticket #86808 : Administration : amélioration de la suppression des albums.
+ 
\ No newline at end of file
diff --git a/library/Class/AlbumCategorie.php b/library/Class/AlbumCategorie.php
index 45725998825..b27da197ad6 100644
--- a/library/Class/AlbumCategorie.php
+++ b/library/Class/AlbumCategorie.php
@@ -269,4 +269,14 @@ class Class_AlbumCategorie extends Storm_Model_Abstract {
        'categories' => $this->getAlbumsInfosForTree($this->getSousCategories()),
        'items' => []];
   }
+
+
+  public function getSousCategoriesIds($ids = []) {
+    $ids [] = $this->getId();
+
+    foreach ($this->getSousCategories() as $sous_categorie)
+      $ids = $sous_categorie->getSousCategoriesIds($ids);
+
+    return $ids;
+  }
 }
\ No newline at end of file
diff --git a/library/Class/AlbumCategorie/Remover.php b/library/Class/AlbumCategorie/Remover.php
new file mode 100644
index 00000000000..a58473a6dfb
--- /dev/null
+++ b/library/Class/AlbumCategorie/Remover.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright (c) 2012-2019, 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_AlbumCategorie_Remover extends Class_Entity {
+
+  use Trait_StaticCommand;
+
+  public function run() {
+    $command = sprintf('delete_album_category.php %s >/dev/null 2>&1 &',
+                       escapeshellarg($this->getId()));
+    $this->getCommand()->execTimedScript(3600, $command);
+    return $this;
+  }
+}
diff --git a/library/ZendAfi/Controller/Plugin/Manager/Album.php b/library/ZendAfi/Controller/Plugin/Manager/Album.php
index d61c405111b..cbb6d598b13 100644
--- a/library/ZendAfi/Controller/Plugin/Manager/Album.php
+++ b/library/ZendAfi/Controller/Plugin/Manager/Album.php
@@ -57,8 +57,13 @@ class ZendAfi_Controller_Plugin_Manager_Album extends ZendAfi_Controller_Plugin_
 
 
   public function deletecategorieAction() {
-    if ($categorie = Class_AlbumCategorie::find((int)$this->_getParam('id')))
-      $categorie->delete();
+    if (!$category = Class_AlbumCategorie::find((int)$this->_getParam('id')))
+      $this->_redirect('admin/album');
+
+    $this->_helper->notify($this->_('La suppression de la catégorie %s a bien été prise en compte.',
+                                    $category->getLibelle()));
+
+    (new Class_AlbumCategorie_Remover(['Id' => $category->getId()]))->run();
     $this->_redirect('admin/album');
   }
 
diff --git a/scripts/delete_album_category.php b/scripts/delete_album_category.php
new file mode 100644
index 00000000000..ce94d558112
--- /dev/null
+++ b/scripts/delete_album_category.php
@@ -0,0 +1,16 @@
+<?php
+require(__DIR__.'/../console.php');
+
+$id = $argv[1];
+
+if (!$category = Class_AlbumCategorie::find($id))
+  exit(1);
+
+while ($albums = Class_Album::findAllBy(['cat_id' => $category->getSousCategoriesIds(),
+                                         'limit' => 500])) {
+  array_map(function($album) { $album->delete();}, $albums);
+  Class_Album::clearCache();
+}
+
+$category->delete();
+?>
\ No newline at end of file
diff --git a/tests/application/modules/admin/controllers/AlbumControllerTest.php b/tests/application/modules/admin/controllers/AlbumControllerTest.php
index c31ce32943d..e8fc2acf476 100644
--- a/tests/application/modules/admin/controllers/AlbumControllerTest.php
+++ b/tests/application/modules/admin/controllers/AlbumControllerTest.php
@@ -46,13 +46,6 @@ abstract class Admin_AlbumControllerTestCase extends Admin_AbstractControllerTes
          ->whenCalled('findAllBy')
          ->answers([$cus, $fre, $dak]);
 
-    $favoris = $this->fixture('Class_AlbumCategorie', ['id' => 2])
-                    ->setParentId(0)
-                    ->setLibelle('Favoris')
-                    ->setSousCategories([])
-                    ->setAlbums([]);
-    $favoris->save();
-
     $adulte = $this->fixture('Class_AlbumCategorie', ['id' => 6])
                    ->setLibelle('Adulte')
                    ->setParentId(2)
@@ -60,6 +53,13 @@ abstract class Admin_AlbumControllerTestCase extends Admin_AbstractControllerTes
                    ->setAlbums([]);
     $adulte->save();
 
+    $favoris = $this->fixture('Class_AlbumCategorie', ['id' => 2])
+                    ->setParentId(0)
+                    ->setLibelle('Favoris')
+                    ->setSousCategories([$adulte])
+                    ->setAlbums([]);
+    $favoris->save();
+
     $patrimoine = $this->fixture('Class_AlbumCategorie', ['id' => 38])
                        ->setParentId(0)
                        ->setSousCategories([])
@@ -541,16 +541,34 @@ class Admin_AlbumControllerEditCategorieFavorisTest extends Admin_AlbumControlle
 class Admin_AlbumControllerDeleteCategorieFavorisTest extends Admin_AlbumControllerTestCase {
   public function setUp() {
     parent::setUp();
+
+    $command = $this
+      ->mock()->beStrict()
+      ->whenCalled('execTimedScript')
+      ->with(3600, 'delete_album_category.php \'2\' >/dev/null 2>&1 &')
+      ->willDo(function()
+               {
+                 Class_AlbumCategorie::find(2)->delete();
+                 Class_AlbumCategorie::clearCache();
+               });
+
+    Class_AlbumCategorie_Remover::setCommand($command);
+
     $this->dispatch('/admin/album/delete_categorie/id/2');
   }
 
-
   /** @test */
-  public function deleteShouldHaveBeenCalledOnFavoris() {
+  public function categoryFavorisShouldHaveBeenDeleted() {
     $this->assertNull(Class_AlbumCategorie::findFirstBy(['libelle'=>'Favoris']));
   }
 
 
+  /** @test */
+  public function adulteShouldHaveBeenDeleted() {
+    $this->assertNull(Class_AlbumCategorie::findFirstBy(['libelle'=>'Adulte']));
+  }
+
+
   /** @test */
   public function shouldRedirectToIndex() {
     $this->assertRedirectTo('/admin/album');
-- 
GitLab