diff --git a/FEATURES/137374 b/FEATURES/137374 new file mode 100644 index 0000000000000000000000000000000000000000..655ce1f8a8932b3f69bee6a22d9097bbc21de1ac --- /dev/null +++ b/FEATURES/137374 @@ -0,0 +1,10 @@ + '137374' => + ['Label' => $this->_('Parcourir l\'étagère'), + 'Desc' => $this->_('Dans les exemplaires, un carrousel de notices représentant les documents sur l\'étagère dans la bibliothèque est disponible à l\'affichage.'), + 'Image' => '', + 'Video' => 'https://youtu.be/WCjz4bFGWeA', + 'Category' => $this->_('Recherche'), + 'Right' => function($feature_description, $user) {return true;}, + 'Wiki' => 'https://wiki.bokeh-library-portal.org/index.php?title=Navigation_par_%C3%A9tag%C3%A8re', + 'Test' => '', + 'Date' => '2022-05-10'], \ No newline at end of file diff --git a/UPGRADE.fr.md b/UPGRADE.fr.md index 98c6c79a0ccdc4ac9a5993f7ffad5fcb00777a79..5261ae89b49b3faa184e71be0b8f15065308e865 100644 --- a/UPGRADE.fr.md +++ b/UPGRADE.fr.md @@ -120,4 +120,6 @@ vous devez procéder à l'étape d'installation de chacune d'elle. - 8.0.159 - 31/05/2020 : Suite à une amélioration de l'ergonomie, le résultat de recherche et la liste des exemplaires dans le magasin de thèmes passent de - l'affichage mur à l'affichage grille. \ No newline at end of file + l'affichage mur à l'affichage grille. + + - 8.0.160 - 20/06/2022 : cosmogramme/sql/patch/patch_433.php \ No newline at end of file diff --git a/VERSIONS_WIP/137374 b/VERSIONS_WIP/137374 new file mode 100644 index 0000000000000000000000000000000000000000..f5c1a4ab4b41c8d38a6f9f30379731b64beede02 --- /dev/null +++ b/VERSIONS_WIP/137374 @@ -0,0 +1 @@ + - fonctionnalité #137374 : Exemplaires : Un carrousel de notices représentant les documents sur l'étagère de la bibliothèque est maintenant disponible. L'affichage de ce dernier se configure dans les paramètres de l'affichage des exemplaires. \ No newline at end of file diff --git a/application/modules/opac/controllers/RechercheController.php b/application/modules/opac/controllers/RechercheController.php index 71f7d6fc80909d57ec87f11f8af0945a4543fdd2..166d9863bae0bf1f69e15a2b363a6bc2c1312aa8 100644 --- a/application/modules/opac/controllers/RechercheController.php +++ b/application/modules/opac/controllers/RechercheController.php @@ -83,6 +83,18 @@ class RechercheController extends ZendAfi_Controller_Action { } + public function shelfAction() { + if (!($item = Class_Exemplaire::find($this->_getParam('item_id')))) + throw new Zend_Controller_Action_Exception($this->view->_('Exemplaire non trouvé'), 404); + + $this->view->content = $this->view->itemShelf(new Class_Exemplaire_Shelf($item)); + + if ('ajax' === $this->_getParam('render')) + $this->_helper->getHelper('HTMLAjaxResponse') + ->htmlAjaxResponseWithScript($this->view->content); + } + + public function saisieAction() { $this->view->expressionRecherche = $this->_request->getParam('expressionRecherche'); } diff --git a/application/modules/opac/views/scripts/recherche/shelf.phtml b/application/modules/opac/views/scripts/recherche/shelf.phtml new file mode 100644 index 0000000000000000000000000000000000000000..ff71d31e883048cb05ea7b632370dd47b1fe1517 --- /dev/null +++ b/application/modules/opac/views/scripts/recherche/shelf.phtml @@ -0,0 +1,2 @@ +<?php +echo $this->content; diff --git a/cosmogramme/php/classes/classe_notice_integration.php b/cosmogramme/php/classes/classe_notice_integration.php index 639069e8246009f24e52354f34e67cd9399e2d5d..bdf5b1ee9b02662689bad233adce111ff02540a4 100644 --- a/cosmogramme/php/classes/classe_notice_integration.php +++ b/cosmogramme/php/classes/classe_notice_integration.php @@ -28,7 +28,9 @@ require_once 'classe_profil_donnees.php'; require_once 'classe_communication.php'; class notice_integration { - use Trait_CodifProviderAware; + use + Trait_CodifProviderAware, + Trait_TimeSource; const RECORD_REJECT = 0, @@ -80,12 +82,11 @@ class notice_integration { $_codification_rules, $_raw_data; - public function __construct() { $this->indexation = indexation::getInstance(); $this->filtrer_fulltext = Class_CosmoVar::get("filtrer_fulltext"); $this->mode_doublon = Class_CosmoVar::get("mode_doublon"); - $this->notice_sgbd = new notice_unimarc(); + $this->notice_sgbd = new notice_unimarc; } @@ -814,7 +815,9 @@ class notice_integration { $this->_deleteAllExemplairesWithSubfield($exemplaires, $id_notice); foreach($exemplaires as $exemplaire) - $exemplaire->save(); + ($exemplaire + ->setShelfKeyUpdateDate($this->getCurrentDateTime()) + ->save()); (new Class_Cosmogramme_Integration_RawRecord($this->_raw_data, $this->notice['id_origine'], diff --git a/cosmogramme/php/integre_traite_main.php b/cosmogramme/php/integre_traite_main.php index fb7c08a8c2e852a9c0d9020bff6c77177f675fee..8c2c9cce0b13f35c8a20562cd2c3d31777c329e0 100644 --- a/cosmogramme/php/integre_traite_main.php +++ b/cosmogramme/php/integre_traite_main.php @@ -257,6 +257,12 @@ if (!$should_skip_records) { // Facets on domains (phase 7.2) // ---------------------------------------------------------------- startIntegrationPhase('DynamicFacetsOnDomainIndex'); + + + // ---------------------------------------------------------------- + // Items Shelf Key generation (phase 7.3) + // ---------------------------------------------------------------- + startIntegrationPhase('ItemsShelfKeyGeneration'); } $phase = 7.5; diff --git a/cosmogramme/sql/patch/patch_434.php b/cosmogramme/sql/patch/patch_434.php new file mode 100644 index 0000000000000000000000000000000000000000..3cc7708c8bdc0a8903f66a24a589d5cba645310b --- /dev/null +++ b/cosmogramme/sql/patch/patch_434.php @@ -0,0 +1,6 @@ +<?php +$adapter = Zend_Db_Table_Abstract::getDefaultAdapter(); + +try { + $adapter->query('ALTER TABLE exemplaires ADD COLUMN shelf_key VARCHAR(255) NULL DEFAULT NULL, ADD COLUMN shelf_key_update_date TIMESTAMP NULL DEFAULT NULL'); +} catch(Exception $e) {} diff --git a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php index 261de58c70bdc1bb6f0a5b3c2320fd3e41e25421..29006511fddb39030f3f1a21592eded5a4e64793 100644 --- a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php +++ b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php @@ -23,6 +23,7 @@ require_once 'classe_notice_integration.php'; require_once 'classe_notice_marc21.php'; require_once 'classe_codif_cache.php'; require_once 'ModelTestCase.php'; +require_once 'tests/library/Class/TimeSourceForTest.php'; abstract class NoticeIntegrationTestCase extends ModelTestCase { @@ -1451,3 +1452,26 @@ class NoticeIntegrationAsservissementConsentiTest extends NoticeIntegrationTestC $this->notice_data['titre_princ']); } } + + + + +class NoticeIntegrationItemsUpdateDateTest extends NoticeIntegrationTestCase { + public function setUp() { + parent::setUp(); + notice_integration::setTimeSource(new TimeSourceForTest('2022-06-20 16:53:17')); + $this->loadNotice("unimarc_musso"); + } + + + public function tearDown() { + notice_integration::setTimeSource(null); + parent::tearDown(); + } + + + /** @test */ + public function itemsShouldHaveShelfKeyUpdateDateSetTo20220620() { + $this->assertEquals(8, Class_Exemplaire::countBy(['shelf_key_update_date' => '2022-06-20 16:53:17'])); + } +} \ No newline at end of file diff --git a/library/Class/Cosmogramme/Integration/Chronometre.php b/library/Class/Cosmogramme/Integration/Chronometre.php index 01ab883f196c6c627fae7e990f41b0ee28c09981..a0094279b18203269b931ba96d53ad057d4d279a 100644 --- a/library/Class/Cosmogramme/Integration/Chronometre.php +++ b/library/Class/Cosmogramme/Integration/Chronometre.php @@ -118,6 +118,11 @@ class Class_Cosmogramme_Integration_Chronometre { } + public function elapsedOnFile() { + return $this->_on_file->elapsed(); + } + + public function mainAverage($number, $label) { return $this->_main->average($number, $label); } diff --git a/library/Class/Cosmogramme/Integration/PhaseAbstract.php b/library/Class/Cosmogramme/Integration/PhaseAbstract.php index 0928e7c2a1dcae65221e44d461f224a29ce88d2a..22b301e31fcbc32fcfba88735efd044182dcd1e7 100644 --- a/library/Class/Cosmogramme/Integration/PhaseAbstract.php +++ b/library/Class/Cosmogramme/Integration/PhaseAbstract.php @@ -21,8 +21,11 @@ abstract class Class_Cosmogramme_Integration_PhaseAbstract { + use Trait_TimeSource, Trait_StaticFileSystem, Trait_Translator, Trait_MemoryCleaner; + protected static $_should_throw_error = false; + protected $_label = '', $_phase, $_log, @@ -92,6 +95,9 @@ abstract class Class_Cosmogramme_Integration_PhaseAbstract { $this->_printLabel(); + if (static::$_should_throw_error) + return $this->_execute(); + try { $this->_execute(); } catch (Exception | Throwable $e) { @@ -217,4 +223,9 @@ abstract class Class_Cosmogramme_Integration_PhaseAbstract { return $this; } + + + public static function shouldThrowError($should) { + static::$_should_throw_error = $should; + } } diff --git a/library/Class/Cosmogramme/Integration/PhaseItemsShelfKeyGeneration.php b/library/Class/Cosmogramme/Integration/PhaseItemsShelfKeyGeneration.php new file mode 100644 index 0000000000000000000000000000000000000000..9d58321b34e76e4ac9a2d007ccdfd0074410c129 --- /dev/null +++ b/library/Class/Cosmogramme/Integration/PhaseItemsShelfKeyGeneration.php @@ -0,0 +1,52 @@ +<?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_Cosmogramme_Integration_PhaseItemsShelfKeyGeneration + extends Class_Cosmogramme_Integration_PhaseAbstract { + + const + MY_ID = 7.3, + MAX_ITEMS = 1000; + + + public function __construct($phase, $log, $chrono) { + parent::__construct($phase, $log, $chrono); + $this->_label = $this->_('Mise à jour des clés d\'étagère des exemplaires'); + } + + + protected function _init($phase) {} + + + protected function _previousPhaseIds() : array { + return [7.2]; + } + + + public function _execute() { + (new Class_Migration_IndexItemsShelfKey) + ->setEchoFunction(fn($message) => $this->_logMessage($message)) + ->run(); + + return $this->_phase; + } +} diff --git a/library/Class/Exemplaire.php b/library/Class/Exemplaire.php index 47e125ed48dfca09869cc4916839c3f989e23570..ec39cb870ead4e0bbb038f6f0ba5faff03e2fb4c 100644 --- a/library/Class/Exemplaire.php +++ b/library/Class/Exemplaire.php @@ -147,7 +147,9 @@ class Class_Exemplaire extends Storm_Model_Abstract { 'id_int_bib' => 0, 'id_data_profile' => 0, 'type' => Class_Notice::TYPE_BIBLIOGRAPHIC, - 'cote' => '']; + 'cote' => '', + 'shelf_key' => '', + 'shelf_key_update_date' => '0000-00-00 00:00:00']; protected $_sigb_exemplaire; @@ -269,6 +271,20 @@ class Class_Exemplaire extends Storm_Model_Abstract { } + public function getClefChapeau() : string { + return ($record = $this->getNotice()) + ? $record->getClefChapeau() + : ''; + } + + + public function getClefAlpha() : string { + return ($record = $this->getNotice()) + ? $record->getClefAlpha() + : ''; + } + + public function getILSWsItem() : Class_WebService_SIGB_Exemplaire { if ( $this->_sigb_exemplaire) return $this->_sigb_exemplaire; @@ -706,4 +722,11 @@ class Class_Exemplaire extends Storm_Model_Abstract { public function isCalendarHoldRequired() : bool { return (bool) $this->_withILSWsItemDo(fn($ils_ws_item) => $ils_ws_item->requiresCalendarHold()); } + + + public function initShelfKey() : self { + return $this->hasCote() + ? $this->setShelfKey((new Class_Exemplaire_ShelfKey)->generateForItem($this)) + : $this; + } } diff --git a/library/Class/Exemplaire/Shelf.php b/library/Class/Exemplaire/Shelf.php new file mode 100644 index 0000000000000000000000000000000000000000..80811344e68e4616ca4e15abc87b396b5fd492e5 --- /dev/null +++ b/library/Class/Exemplaire/Shelf.php @@ -0,0 +1,69 @@ +<?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_Exemplaire_Shelf { + + protected Class_Exemplaire $_item; + + public function __construct(Class_Exemplaire $item) { + $this->_item = $item; + } + + + public function getBibLibelle() : string { + return $this->_item->getBibLibelle(); + } + + + public function renderOn(Callable $callback) : string { + return $callback($this->_findBeforeItems(), + $this->_item, + $this->_findAfterItems()); + } + + + protected function _findBeforeItems() : array { + return array_reverse($this->_findItems(Class_Exemplaire::clauseLesser('shelf_key', + $this->_item->getShelfKey()), + 'shelf_key desc')); + } + + + protected function _findAfterItems() : array { + return $this->_findItems(Class_Exemplaire::clauseGreater('shelf_key', + $this->_item->getShelfKey()), + 'shelf_key'); + } + + + protected function _findItems(Storm_Model_PersistenceStrategy_Clause $clause, + string $order) : array { + return Class_Exemplaire::findAllBy([$clause, + 'order' => $order, + 'id_bib' => $this->_item->getIdBib(), + 'section' => $this->_item->getSection(), + 'emplacement' => $this->_item->getEmplacement(), + 'id_notice not' => $this->_item->getIdNotice(), + 'limit' => 12, + 'group_by' => 'id_notice']); + } +} diff --git a/library/Class/Exemplaire/ShelfKey.php b/library/Class/Exemplaire/ShelfKey.php new file mode 100644 index 0000000000000000000000000000000000000000..f8e768a7b2b07c513f50cf58cc0e094c76556f83 --- /dev/null +++ b/library/Class/Exemplaire/ShelfKey.php @@ -0,0 +1,77 @@ +<?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_Exemplaire_ShelfKey { + + protected int $_subkey_len = 4; + protected int $_keyparts_count = 6; + + /** + * Generate a key to order items on a virtual shelf + * + * Example: + * for item 'id' => 111, 'cote' => 'AMT R GER 740.1 698', '' + * and Record 'tome_alpha' => '365', 'clef_alpha' => 'OTHERTITLE', 'clef_chapeau' => 'KEYCHAPEAU', + * => 0AMT_000R_0GER_0740_0001_0698_KEYCHAPE_0365_OTHERTIT_0111 + */ + public function generateForItem(Class_Exemplaire $item) : string { + return $this->generateForArray(['cote' => $item->getCote(), + 'clef_chapeau' => $item->getClefChapeau(), + 'tome_alpha' => $item->getTomeAlpha(), + 'clef_alpha' => $item->getClefAlpha(), + 'id' => $item->getId()]); + } + + + public function generateForArray(array $row) : string { + $parts = $this->_coteKeyParts($row['cote']); + $parts [] = $this->_padLeft($row['clef_chapeau'], $this->_subkey_len * 2); + $parts [] = $this->_padLeft($row['tome_alpha'], $this->_subkey_len); + $parts [] = $this->_padLeft($row['clef_alpha'], $this->_subkey_len * 2); + $parts [] = str_pad(substr($row['id'], + -$this->_subkey_len), + $this->_subkey_len, + '0', + STR_PAD_LEFT); + + return implode('_', $parts); + } + + + protected function _padLeft(string $part, int $length) : string { + return str_pad(substr($part, 0, $length), + $length, + '0', + STR_PAD_LEFT); + } + + + protected function _coteKeyParts(string $cote) : array { + return array_map(fn($key) => $this->_padLeft($key, $this->_subkey_len), + array_pad(array_slice(explode(' ', + Class_Indexation::getInstance()->alphaMaj($cote)), + 0, + $this->_keyparts_count), + $this->_keyparts_count, + '')); + } +} \ No newline at end of file diff --git a/library/Class/Indexation/PseudoNotice.php b/library/Class/Indexation/PseudoNotice.php index 3585a9835aa1cdbb4beb01d1facdaebf0e39bbac..8c7898433b2b4b4081186ec584d17b8cb1339e4a 100644 --- a/library/Class/Indexation/PseudoNotice.php +++ b/library/Class/Indexation/PseudoNotice.php @@ -166,9 +166,10 @@ class Class_Indexation_PseudoNotice { } $this->_exemplaire = Class_Exemplaire::newInstance(['id_bib' => $this->_datas['id_bib'], - 'id_notice' => $this->_notice->getId(), + 'notice' => $this->_notice, 'id_origine' => $this->_model->getId(), 'activite' => $this->_('A consulter sur le portail')]); + if ($this->_exemplaire->save()) { $this->_notice->addExemplaire($this->_exemplaire); return true; diff --git a/library/Class/Migration/IndexItemsShelfKey.php b/library/Class/Migration/IndexItemsShelfKey.php new file mode 100644 index 0000000000000000000000000000000000000000..62c8069bb77423c87ff98a90646e91ca5ecc5082 --- /dev/null +++ b/library/Class/Migration/IndexItemsShelfKey.php @@ -0,0 +1,147 @@ +<?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_Migration_IndexItemsShelfKey { + + use + Trait_TimeSource, + Trait_EchoError, + Trait_Translator, + Trait_MemoryCleaner; + + + protected Class_Exemplaire_ShelfKey $_shelf_key_generator; + protected Class_Cosmogramme_Integration_Chronometre $_chrono; + protected string $_current_date_time = ''; + protected int $_page_size = 5000; + + + public function run() : void { + $this->_chrono = (new Class_Cosmogramme_Integration_Chronometre)->startMain(); + + $this->echoStartTitle($this->_('Début de la phase d\'indexation des clés d\'étagères des exemplaires')); + + $this->_shelf_key_generator = new Class_Exemplaire_ShelfKey; + $this->_current_date_time = $this->getCurrentDateTime(); + $this->_sql = Zend_Registry::get('sql'); + + $this->_run(); + + Class_CosmoVar::setValueOf('shelf_key_update_date', $this->_current_date_time); + + $this->echoEndTitle($this->_('Fin de la phase d\'indexation des clés d\'étagères. Durée : %ss' , + $this->_chrono->mainElapsed())); + } + + + protected function _run() : self { + $this->_chrono->startOnFile(); + $title = $this->_('Indexation des clés'); + $this->echoStartTitle($title); + + $where_clause = + sprintf('exemplaires.cote > \'\' AND ' + . '( exemplaires.shelf_key IS NULL ' + . 'OR exemplaires.shelf_key = \'\' ' + . 'OR ( exemplaires.shelf_key_update_date > \'%s\' ' + . 'AND exemplaires.shelf_key_update_date < \'%s\' ))', + Class_CosmoVar::getValueOf('shelf_key_update_date') ?? '0000-00-00 00:00:00', + $this->_current_date_time); + + $select_columns = + sprintf('select exemplaires.id, exemplaires.id_notice, ' + . 'exemplaires.cote, notices.clef_chapeau, notices.tome_alpha, ' + . 'notices.clef_alpha ' + . 'from exemplaires inner join notices on exemplaires.id_notice = notices.id_notice ' + . 'where %s limit %d', + $where_clause, + $this->_page_size); + + $count_result = + $this->_sql->fetchAllByColumn(sprintf('select count(exemplaires.id) from exemplaires where %s', $where_clause)); + $count = reset($count_result); + + $this->echoError($this->_('Nombre de clés à indexer : %d', $count) . "\n"); + + if ( 0 === $count) + return $this; + + $page_count = 0; + $total_pages = (int) ceil(($count / $this->_page_size)); + + while ($page = $this->_sql->fetchAll($select_columns)) { + $page_count++; + + if ( $page_count > $total_pages ) { + $this->echoEndTitle($this->_('%s stopée.', + $title)); + return $this; + } + + $this->_runPage($page, $page_count, $total_pages); + } + + $this->echoOK(); + $this->echoEndTitle($this->_('%s traitée en %ss', + $title, + $this->_chrono->elapsedOnFile())); + return $this; + } + + + protected function _runPage(array $page, int $count, int $total) : void { + $this->_chrono->startOnRecords(); + $this->echoError($this->_('page de %d exemplaires : %d/%d', + count($page), + $count, + $total)); + + $update_items = + sprintf('update exemplaires ' + . 'set shelf_key = (CASE %s ELSE shelf_key END), shelf_key_update_date = \'%s\' ' + . 'WHERE id in (%s)', + $this->_whenThenForPage($page), + $this->_current_date_time, + $this->_idsForWhere($page)); + + $this->_sql->execute($update_items); + + $this->echoError($this->_(' en %ss', $this->_chrono->elapsedOnRecords()) . "\n"); + } + + + protected function _whenThenForPage(array $page) : string { + return implode(' ', array_map(fn($row) => $this->_whenThenForRow($row), $page)); + } + + + protected function _whenThenForRow(array $row) : string { + return sprintf('WHEN (id = "%s") THEN "%s"', + $row['id'], + $this->_shelf_key_generator->generateForArray($row)); + } + + + protected function _idsForWhere(array $page) { + return implode(',', array_map(fn($row) => $row['id'], $page)); + } +} \ No newline at end of file diff --git a/library/Class/Profil/ItemsSettings.php b/library/Class/Profil/ItemsSettings.php index c6c4d7ab43b37b3ea4e27c40f0d103ce3faf4246..7f644e03faa7bb13eeb45e1e077fd3e4de1e3c0f 100644 --- a/library/Class/Profil/ItemsSettings.php +++ b/library/Class/Profil/ItemsSettings.php @@ -48,6 +48,11 @@ class Class_Profil_ItemsSettings { } + public function isItemsShelfEnabled() : bool { + return (bool) ($this->_settings['enable_items_shelf'] ?? 0); + } + + public function setSettings($settings) { $this->_settings = array_merge($this->_settings, $settings); diff --git a/library/Class/Template/Update.php b/library/Class/Template/Update.php index 71e3056266cf5590b6dd2fdd545c065f840540f6..7f0ee0de366188502ae7aea060150ce1c18932a6 100644 --- a/library/Class/Template/Update.php +++ b/library/Class/Template/Update.php @@ -43,11 +43,4 @@ class Class_Template_Update { $this->echoEndTitle($this->_('Fin de la mise à jour des thèmes du magasin')); } - - - public function runWithEcho(bool $echo) : self { - $this->setEcho($echo); - $this->run(); - return $this; - } } diff --git a/library/Trait/EchoError.php b/library/Trait/EchoError.php index 7039e34e26ef0745212feb17e371a58ec9935134..cadcd1ee6daaad51c0c1ac5f4fd8139240d954e5 100644 --- a/library/Trait/EchoError.php +++ b/library/Trait/EchoError.php @@ -21,14 +21,24 @@ trait Trait_EchoError { - protected static $_echo; - - public function echoError($error) { - return call_user_func(function($args) { - if(!self::$_echo) - echo $args; - return $args; - },$error); + + protected $_echo_function; + + + public function setEchoFunction(Closure $echo_function) : self { + $this->_echo_function = $echo_function; + return $this; + } + + + public function echoError($message) : self { + if ($this->_echo_function) { + call_user_func($this->_echo_function, $message); + return $this; + } + + echo $message; + return $this; } @@ -47,7 +57,9 @@ trait Trait_EchoError { } - public static function setEcho($echo) { - self::$_echo = $echo; + public function runWithoutEcho() : self { + $this->setEchoFunction(fn() => null); + call_user_func_array([$this, 'run'], func_get_args()); + return $this; } } \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Notice/Unimarc.php b/library/ZendAfi/View/Helper/Notice/Unimarc.php index 2a9d0b56041cce486f7b8cd0c1bad118904c2859..87f9a75d3113550c5526f55394099de8f7bec263 100644 --- a/library/ZendAfi/View/Helper/Notice/Unimarc.php +++ b/library/ZendAfi/View/Helper/Notice/Unimarc.php @@ -136,7 +136,8 @@ class ZendAfi_View_Helper_Notice_Unimarc extends Zend_View_Helper_HtmlElement { 'getIdOrigine' => $this->_('Id origine'), 'getIdDataProfile' => $this->_('Profil de données'), 'getDateNouveaute' => $this->_('Date nouveauté'), - 'getIdIntBib' => $this->_('Intégration programmée')]; + 'getIdIntBib' => $this->_('Intégration programmée'), + 'getShelfKey' => $this->_('Clé étagère')]; $html = ''; foreach($notice->getExemplaires() as $item) diff --git a/library/ZendAfi/View/Helper/Template/BadgeGroup.php b/library/ZendAfi/View/Helper/Template/BadgeGroup.php index 501ea2ce9ee460d2ca8349fa74dc5903823c9493..c5912a798bb8870f0641ee95c23a390efacd4e7f 100644 --- a/library/ZendAfi/View/Helper/Template/BadgeGroup.php +++ b/library/ZendAfi/View/Helper/Template/BadgeGroup.php @@ -38,6 +38,9 @@ class ZendAfi_View_Helper_Template_BadgeGroup extends ZendAfi_View_Helper_BaseHe if ($url = $badge->getUrl()) $attribs['href'] = $url; + if ($on_click = $badge->getOnClick()) + $attribs['onclick'] = $on_click; + $img = ($img = $badge->getImage()) ? $img : ''; diff --git a/library/ZendAfi/View/Helper/Template/ItemShelf.php b/library/ZendAfi/View/Helper/Template/ItemShelf.php new file mode 100644 index 0000000000000000000000000000000000000000..df6b485f56b8b0cf927aa3ab586e5b3c94667371 --- /dev/null +++ b/library/ZendAfi/View/Helper/Template/ItemShelf.php @@ -0,0 +1,78 @@ +<?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 ZendAfi_View_Helper_Template_ItemShelf + extends ZendAfi_View_Helper_BaseHelper { + + public function itemShelf(Class_Exemplaire_Shelf $shelf) : string { + return + $this->_tag('h2', $this->_('Étagère de la bibliothèque %s', + $shelf->getBibLibelle())) + . + $shelf->renderOn(fn($before, $item, $after) => $this->_renderShelf($before, $item, $after)); + } + + + protected function _renderShelf(array $before_items, + Class_Exemplaire $selected_item, + array $after_items) : string { + + return $this->view + ->renderMultipleCarousel($this->_itemsToWrappedRecords([...$before_items, + $selected_item, + ...$after_items]), + + fn($record_wrapper) => $this->_renderRecord($record_wrapper, + $selected_item), + (new Intonation_Library_Widget_Carousel_Settings) + ->setColumns(5) + ->setActivePage((int)(count($before_items) / 5))); + } + + + protected function _itemsToWrappedRecords(array $items) : Storm_Model_Collection { + $records = new Storm_Model_Collection; + foreach($items as $item) + $records->add((new Intonation_Library_View_Wrapper_Record($item->getNotice())) + ->setView($this->view)); + + return $records; + } + + + protected function _renderRecord(Intonation_Library_View_Wrapper_Record $record_wrapper, Class_Exemplaire $selected_item) : string { + return $record_wrapper->getId() === $selected_item->getIdNotice() + ? $this->_renderRecordEmphasized($record_wrapper) + : $this->view->renderingOnlyImage($record_wrapper); + } + + + protected function _renderRecordEmphasized(Intonation_Library_View_Wrapper_Record $record_wrapper) : string { + return (new class() extends ZendAfi_View_Helper_Template_RenderingOnlyImage { + protected function _cardClass() : string { + return parent::_cardClass() . ' shelf_current_item'; + } + }) + ->setView($this->view) + ->renderingOnlyImage($record_wrapper); + } +} diff --git a/library/ZendAfi/View/Helper/Template/Jumbotron.php b/library/ZendAfi/View/Helper/Template/Jumbotron.php index 63dca1ddf5eea9820ab5fa3817b900dfe0869c14..058ceba3b181f42c138856a3801691f6e180788a 100644 --- a/library/ZendAfi/View/Helper/Template/Jumbotron.php +++ b/library/ZendAfi/View/Helper/Template/Jumbotron.php @@ -235,9 +235,7 @@ class ZendAfi_View_Helper_Template_Jumbotron extends ZendAfi_View_Helper_BaseHel protected function _renderLoadingIcon() { - return $this->_div(['class' => 'col-12 text-center'], - $this->_div(['class' => 'loading_icon'], - $this->view->screenReaderOnly($this->_('Merci de patientier...')))); + return $this->view->loadingIcon(); } diff --git a/library/ZendAfi/View/Helper/Template/LayoutCarousel.php b/library/ZendAfi/View/Helper/Template/LayoutCarousel.php index bf535f79c0e79a9da0ba18c81416c60df262fa74..041bd202155b2b601070ef32a5c736e487d69eb0 100644 --- a/library/ZendAfi/View/Helper/Template/LayoutCarousel.php +++ b/library/ZendAfi/View/Helper/Template/LayoutCarousel.php @@ -22,8 +22,10 @@ class ZendAfi_View_Helper_Template_LayoutCarousel extends Intonation_View_Abstract_Carousel { - public function layoutCarousel($collection, $callback = null) { - return $this->_renderCarousel($collection, $callback); + public function layoutCarousel($collection, + $callback = null, + Intonation_Library_Widget_Carousel_Settings $settings) { + return $this->_renderCarousel($collection, $callback, $settings); } @@ -40,4 +42,4 @@ class ZendAfi_View_Helper_Template_LayoutCarousel extends Intonation_View_Abstra protected function _shouldShowControls($collection) { return 1 < $this->_numberOfPages($collection); } -} \ No newline at end of file +} diff --git a/library/ZendAfi/View/Helper/Template/LoadingIcon.php b/library/ZendAfi/View/Helper/Template/LoadingIcon.php new file mode 100644 index 0000000000000000000000000000000000000000..e9be8d7f14605624f50c9bee57ecfd35e913519c --- /dev/null +++ b/library/ZendAfi/View/Helper/Template/LoadingIcon.php @@ -0,0 +1,29 @@ +<?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 ZendAfi_View_Helper_Template_LoadingIcon extends ZendAfi_View_Helper_BaseHelper { + public function loadingIcon() : string { + return $this->_div(['class' => 'col-12 text-center'], + $this->_div(['class' => 'loading_icon'], + $this->view->screenReaderOnly($this->_('Merci de patientier...')))); + } +} \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Template/RenderingOnlyImage.php b/library/ZendAfi/View/Helper/Template/RenderingOnlyImage.php index 5ef02f205fba4a1f0f95d9f332ca9f74d96f3661..6087128798bb1dc2cfb497e4cf038d2c18fffb56 100644 --- a/library/ZendAfi/View/Helper/Template/RenderingOnlyImage.php +++ b/library/ZendAfi/View/Helper/Template/RenderingOnlyImage.php @@ -27,7 +27,12 @@ class ZendAfi_View_Helper_Template_RenderingOnlyImage return $this->_tag('div', $element->getAnchor() . $this->_cardWithPicture($element), - ['class' => 'card_with_overlay']); + ['class' => $this->_cardClass()]); + } + + + protected function _cardClass() : string { + return 'card_with_overlay'; } diff --git a/library/storm b/library/storm index c153d5d9c58e5823df94410ee1c6ae321d2bf51b..55dd4c19b54eead3f8a06871cbca07d582973427 160000 --- a/library/storm +++ b/library/storm @@ -1 +1 @@ -Subproject commit c153d5d9c58e5823df94410ee1c6ae321d2bf51b +Subproject commit 55dd4c19b54eead3f8a06871cbca07d582973427 diff --git a/library/templates/Chili/View/Abonne.php b/library/templates/Chili/View/Abonne.php index 1a78a3b1379b2782bfab068abb119ab956ae60c0..4eca0ce96bed41d12a2a65bbc446c96c88f9cae6 100644 --- a/library/templates/Chili/View/Abonne.php +++ b/library/templates/Chili/View/Abonne.php @@ -51,9 +51,11 @@ class Chili_View_Abonne extends ZendAfi_View_Helper_BaseHelper { protected function _renderCarouselForSmallScreen($sections) { - $content = $this->view->renderMultipleCarousel($sections, - [$this->view, 'renderingVertical'], - 3); + $content = + $this->view->renderMultipleCarousel($sections, + [$this->view, 'renderingVertical'], + ((new Intonation_Library_Widget_Carousel_Settings) + ->setColumns(3))); return $this->_div(['class' => 'big_buttons_sm'], $content); diff --git a/library/templates/Chili/View/AbstractHighlightCarousel.php b/library/templates/Chili/View/AbstractHighlightCarousel.php index 0455dacbd518ff50339d283d7210084854d643fe..fb3ca13f13b1ccd18fe121b068ffc97db462e716 100644 --- a/library/templates/Chili/View/AbstractHighlightCarousel.php +++ b/library/templates/Chili/View/AbstractHighlightCarousel.php @@ -20,66 +20,77 @@ */ -class Chili_View_AbstractHighlightCarousel extends Intonation_View_RenderMultipleCarousel { +class Chili_View_AbstractHighlightCarousel + extends Intonation_View_RenderMultipleCarousel { - protected - $_columns, - $_highlight_class, + protected $_highlight_class, $_highlight_column_class, $_columns_class; - protected function _renderCarousel($collection, $callback) { + protected function _renderCarousel(Storm_Collection $collection, + ?Callable $callback, + Intonation_Library_Widget_Carousel_Settings $settings) { + if ($collection->isEmpty()) + return ''; + + $this->_settings = $settings; + $html = [$this->_div(['class' => 'highlight_carousel_xl'], - parent::_renderCarousel($collection, $callback)), + parent::_renderCarousel($collection, $callback, $settings)), $this->_div(['class' => 'highlight_carousel_md'], - $this->view->renderMultipleCarousel($collection, $callback, 3)), + $this->view->renderMultipleCarousel($collection, + $callback, + $settings->setColumns(3))), $this->_div(['class' => 'highlight_carousel_sm'], - $this->view->layoutCarousel($collection, $callback))]; + $this->view->layoutCarousel($collection, + $callback, + $settings->setColumns(1)))]; return $this->view->grid($html); } - protected function _carouselInner($collection, $id, $callback) { + protected function _carouselInner(Storm_Collection $collection, + string $id, + Callable $callback) : string { $cards = array_filter($collection->injectInto([], function($html, $element) use ($callback) { $count = count($html); - $html [] = ($count % $this->_columns != 0) + $html [] = ($count % $this->_settings->getColumns() != 0) ? $callback($element) : $this->view->highlightCardify($element); return $html; })); - return Intonation_View_Abstract_Carousel::_carouselInner($this->_gridify($cards), $id, function ($element) - { - return $element; - }); + return Intonation_View_Abstract_Carousel::_carouselInner($this->_gridify($cards), + $id, + fn($element) => $element); } protected function _gridify($elements) { - $number_of_rows = ceil(count($elements) / $this->_columns); + $number_of_rows = ceil(count($elements) / $this->_settings->getColumns()); $rows = []; for ($i = 0; $i < $number_of_rows; $i++) { $items = array_slice($elements, - $i * $this->_columns, - $this->_columns); + $i * $this->_settings->getColumns(), + $this->_settings->getColumns()); $highlight = array_shift($items); $collection_html = $this->_tag('div', implode($items), - ['class' => $this->_getWrapperClass($items, $this->_columns - 1)]); + ['class' => $this->_getWrapperClass($items, $this->_settings->getColumns() - 1)]); $rows [$i] = $this->view->grid(implode([$this->view->div(['class' => $this->_highlight_column_class], - $highlight), - $this->view->div(['class' => $this->_columns_class], - $collection_html)])); + $highlight), + $this->view->div(['class' => $this->_columns_class], + $collection_html)])); } return new Storm_Collection($rows); diff --git a/library/templates/Chili/View/RenderLeftHighlightCarousel.php b/library/templates/Chili/View/RenderLeftHighlightCarousel.php index b44ab67f533470877288aaa1b3e5a6c156ded2c4..bfeeff07eec9482b9b626b33fd229b87089d05a7 100644 --- a/library/templates/Chili/View/RenderLeftHighlightCarousel.php +++ b/library/templates/Chili/View/RenderLeftHighlightCarousel.php @@ -20,16 +20,18 @@ */ -class Chili_View_RenderLeftHighlightCarousel extends Chili_View_AbstractHighlightCarousel { +class Chili_View_RenderLeftHighlightCarousel + extends Chili_View_AbstractHighlightCarousel { - protected - $_columns = 4, - $_highlight_class = 'left_highlight_carousel', + protected $_highlight_class = 'left_highlight_carousel', $_highlight_column_class = 'left_highlight_column', $_columns_class = 'left_carousel_columns'; public function renderLeftHighlightCarousel($elements, $content_callback) { - return $this->_renderCarousel($elements, $content_callback); + return $this->_renderCarousel($elements, + $content_callback, + ((new Intonation_Library_Widget_Carousel_Settings) + ->setColumns(4))); } } diff --git a/library/templates/Chili/View/RenderMultipleCarousel.php b/library/templates/Chili/View/RenderMultipleCarousel.php index 91b03eca6ca5ce649f6822c9d33d03e02a22fb31..67a65582b768681bd1febf3803860be2988b2328 100644 --- a/library/templates/Chili/View/RenderMultipleCarousel.php +++ b/library/templates/Chili/View/RenderMultipleCarousel.php @@ -20,22 +20,37 @@ */ -class Chili_View_RenderMultipleCarousel extends Intonation_View_RenderMultipleCarousel { +class Chili_View_RenderMultipleCarousel + extends Intonation_View_RenderMultipleCarousel { + + protected function _renderCarousel($collection, + $callback, + Intonation_Library_Widget_Carousel_Settings $settings) { + + if ($collection->isEmpty()) + return ''; + + $this->_settings = $settings; - protected function _renderCarousel($collection, $callback) { $md_helper = (new Intonation_View_RenderMultipleCarousel) ->setView($this->view); $html = [ - $this->_div(['class' => 'col-12 d-none d-lg-block'], parent::_renderCarousel($collection, $callback)), + $this->_div(['class' => 'col-12 d-none d-lg-block'], + parent::_renderCarousel($collection, + $callback, + $settings->setColumns(5))), $this->_div(['class' => 'col-12 d-none d-md-block d-lg-none'], $md_helper->renderMultipleCarousel($collection, $callback, - 3)), + ($settings + ->setColumns(3)))), - $this->_div(['class' => 'col-12 d-block d-md-none'], $this->view->layoutCarousel($collection, $callback)), - ]; + $this->_div(['class' => 'col-12 d-block d-md-none'], + $this->view->layoutCarousel($collection, + $callback, + $settings->setColumns(1)))]; return $this->view->grid($html, ['class' => 'responsive_multiple_carousel']); } diff --git a/library/templates/Chili/View/RenderTopHighlightCarousel.php b/library/templates/Chili/View/RenderTopHighlightCarousel.php index 0c2d6a87dc1ec94fdb5b85a4c75a8d3cc0e965e5..729291c8276f5f208d095b8cd294fa91188016b7 100644 --- a/library/templates/Chili/View/RenderTopHighlightCarousel.php +++ b/library/templates/Chili/View/RenderTopHighlightCarousel.php @@ -20,16 +20,17 @@ */ -class Chili_View_RenderTopHighlightCarousel extends Chili_View_AbstractHighlightCarousel { +class Chili_View_RenderTopHighlightCarousel + extends Chili_View_AbstractHighlightCarousel { - protected - $_columns = 6, - $_highlight_class = 'top_highlight_carousel', + protected $_highlight_class = 'top_highlight_carousel', $_highlight_column_class = 'top_highlight_column', $_columns_class = 'top_carousel_columns'; public function renderTopHighlightCarousel($elements, $content_callback) { - return $this->_renderCarousel($elements, $content_callback); + return $this->_renderCarousel($elements, + $content_callback, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(6)); } -} \ No newline at end of file +} diff --git a/library/templates/Chili/View/RenderWall.php b/library/templates/Chili/View/RenderWall.php index dcd457d567a8ffff987490c099b8b5313e09b0cf..0887f94d2e3d05b0c1c2dd0a179f0ad9ae247c79 100644 --- a/library/templates/Chili/View/RenderWall.php +++ b/library/templates/Chili/View/RenderWall.php @@ -36,11 +36,14 @@ class Chili_View_RenderWall extends Intonation_View_RenderWall { protected function _renderHtml($html) { - $html = [$this->_div(['class' => 'wall_grid_lg'], - parent::_renderHtml($html)), - - $this->_div(['class' => 'wall_grid_md'], - $this->view->renderMultipleCarousel($this->_collection, $this->_callback, 3))]; + $html = + [$this->_div(['class' => 'wall_grid_lg'], + parent::_renderHtml($html)), + + $this->_div(['class' => 'wall_grid_md'], + $this->view->renderMultipleCarousel($this->_collection, + $this->_callback, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(3)))]; return $this->view->grid($html); } diff --git a/library/templates/Herisson/Assets/css/herisson.css b/library/templates/Herisson/Assets/css/herisson.css index c9ef5c34e129ecb67ecf9ec422b5e1d60a11fb7d..6e40b5d6d7a2aeae7efd8ca3f072c14e6bf97edc 100644 --- a/library/templates/Herisson/Assets/css/herisson.css +++ b/library/templates/Herisson/Assets/css/herisson.css @@ -1106,6 +1106,11 @@ h2.jumbotron_section_title * { min-width: 100px; } +a.badge_tag.badge-secondary { + background-color: var(--background-very-dark); + border-color: var(--background-very-dark); +} + /*fiche bib*/ .wrapper_library_openings .default_opening_hours h3 { diff --git a/library/templates/Intonation/Assets/css/intonation.css b/library/templates/Intonation/Assets/css/intonation.css index 7e1d8b61067304b146f94588938d390246305d51..dceef44bcf29dc24337a6527b9af6a320103e8c5 100644 --- a/library/templates/Intonation/Assets/css/intonation.css +++ b/library/templates/Intonation/Assets/css/intonation.css @@ -1149,3 +1149,13 @@ button.view_more_record_actions, .navbar_toggler_text { display: none; } + +#items_shelf .card_with_overlay { + height: 80%; + margin: auto; +} + +#items_shelf .card_with_overlay.shelf_current_item { + height: 90%; + box-shadow: 0px 0px 20px 1px --front-shadow; +} diff --git a/library/templates/Intonation/Assets/js/item_shelf/item_shelf.js b/library/templates/Intonation/Assets/js/item_shelf/item_shelf.js new file mode 100644 index 0000000000000000000000000000000000000000..f28afccaa755ebaf0f7efbe9424398282047c796 --- /dev/null +++ b/library/templates/Intonation/Assets/js/item_shelf/item_shelf.js @@ -0,0 +1,10 @@ +(function ( $ ) { + $.fn.item_shelf = function(event) { + event.preventDefault(); + var link = $(this).closest('a'); + var url = link.attr("href"); + var items_shelf = $("#items_shelf"); + items_shelf.addClass('loading_data'); + items_shelf.load(url + "/render/ajax", () => items_shelf.removeClass('loading_data')); + }; +} (jQuery)); diff --git a/library/templates/Intonation/Assets/js/item_shelf/item_shelf_tests.html b/library/templates/Intonation/Assets/js/item_shelf/item_shelf_tests.html new file mode 100644 index 0000000000000000000000000000000000000000..baca0f8d9bf89a891c20e72a69b84c5372ead19d --- /dev/null +++ b/library/templates/Intonation/Assets/js/item_shelf/item_shelf_tests.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<!-- + /** + * Copyright (c) 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 + */ + --> +<html> + <head> + <meta charset="utf-8"> + <title>Item Shelf tests</title> + <link rel="stylesheet" href="../../../../../../public/qunit-git.css"> + + <script src="../../../../../../public/qunit-1.13.0.js"></script> + <script src="../../../../../../public/admin/js/jquery-3.6.0.min.js"></script> + + <script src="item_shelf.js"></script> + <script src="item_shelf_tests.js"></script> + + </head> + <body> + <div id="qunit"></div> + <div > + <a title="Parcourir l'étagère de la bibliothèque Astrolabe" class="badge_tag browse_shelf text-left badge badge-secondary" href="/recherche/shelf/item_id/999999" onclick="$(this).item_shelf(event);"><i class="fas fa-glasses" aria-hidden="true"></i><span class="badge_text align-middle d-inline-block text-left"><span class="sr-only"> de la bibliothèque Astrolabe</span>Parcourir l'étagère</span></a> + <div id="items_shelf" class="items_shelf col-12"></div> + </div> +</head> +</html> diff --git a/library/templates/Intonation/Assets/js/item_shelf/item_shelf_tests.js b/library/templates/Intonation/Assets/js/item_shelf/item_shelf_tests.js new file mode 100644 index 0000000000000000000000000000000000000000..9d447dd7cdae45e07ddab88cb057a3c3d3e36a2e --- /dev/null +++ b/library/templates/Intonation/Assets/js/item_shelf/item_shelf_tests.js @@ -0,0 +1,52 @@ +/** + * 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 + */ + + +QUnit.module('item_shelf'); + +var expected_url; +var delayed_callback; + + +moduleStart( () => { + $.fn.load = (url, callback) => { + expected_url = url; + delayed_callback = callback; + }; +}); + + +test('click on anchor should add class loading_data to div id items_shelf', () => { + $("a").click(); + deepEqual($('#items_shelf.loading_data').length, 1); +}); + + +test('click on anchor should call jquery load with url /recherche/shelf/item_id/999999/render/ajax', () => { + $("a").click(); + deepEqual(expected_url, '/recherche/shelf/item_id/999999/render/ajax'); +}); + + +test('click on anchor after load should remove class loading_data from div id items_shelf', () => { + $("a").click(); + delayed_callback(); + deepEqual($('#items_shelf:not(.loading_data)').length, 1); +}); diff --git a/library/templates/Intonation/Library/Badge.php b/library/templates/Intonation/Library/Badge.php index 737fa92fc3d31c46ffa60b2fa142a516b4245f1d..9af935cd199002a767ff30fc9cea2ee4f95b207b 100644 --- a/library/templates/Intonation/Library/Badge.php +++ b/library/templates/Intonation/Library/Badge.php @@ -28,7 +28,8 @@ class Intonation_Library_Badge { $_image, $_class = 'secondary', $_tag = 'span', - $_url; + $_url, + $_on_click; public function setText($text) { @@ -86,13 +87,24 @@ class Intonation_Library_Badge { } - public function setUrl($url) { + public function setUrl(string $url) : self { $this->_url = $url; return $this; } - public function getUrl() { + public function getUrl() : ?string { return $this->_url; } + + + public function setOnClick(string $code) : self { + $this->_on_click = $code; + return $this; + } + + + public function getOnClick() : string { + return $this->_on_click ?? ''; + } } diff --git a/library/templates/Intonation/Library/FormCustomizer/RecordItems.php b/library/templates/Intonation/Library/FormCustomizer/RecordItems.php index 66316bab09714fa2c9ae2efaf0205922ee69638b..932197a1a0bd364f0afd1e92662e816f0b03c670 100644 --- a/library/templates/Intonation/Library/FormCustomizer/RecordItems.php +++ b/library/templates/Intonation/Library/FormCustomizer/RecordItems.php @@ -37,11 +37,15 @@ class Intonation_Library_FormCustomizer_RecordItems extends Intonation_Library_F $this->_form->addElement('checkbox', 'all_items_map', ['label' => $this->_('Afficher la carte des exemplaires')]) + ->addElement('checkbox', + 'enable_items_shelf', + ['label' => $this->_('Activer la navigation par étagère')]) ->addElement('number', 'pagination_threshold', ['label' => $this->_('Pagine les exemplaires à partir de'), 'value' => 200]) ->addToDisplayGroup(['all_items_map', + 'enable_items_shelf', 'pagination_threshold'], 'items_fieldset'); return $this->_form; diff --git a/library/templates/Intonation/Library/Settings.php b/library/templates/Intonation/Library/Settings.php index 161225ec10ca8682e1e0b080607c699da604cb18..35ddda527e6474dd35420e7614faba0c9a41f493 100644 --- a/library/templates/Intonation/Library/Settings.php +++ b/library/templates/Intonation/Library/Settings.php @@ -344,6 +344,8 @@ class Intonation_Library_Settings extends Intonation_System_Abstract { 'span class danger' => 'badge-danger text-light', 'span class success' => 'badge-success text-light', 'span class warning' => 'badge-warning text-dark', + 'a class browse_shelf' => 'badge-secondary', + 'div class items_shelf' => 'col-12', ], 'icons_map_doc_types' => [], diff --git a/library/templates/Intonation/Library/View/Wrapper/Item.php b/library/templates/Intonation/Library/View/Wrapper/Item.php index 888f531ac7ee632fcc4bf6c3c258112c3489c4cf..2c6bcbe3b6904c378a944d734853dfe237b97cce 100644 --- a/library/templates/Intonation/Library/View/Wrapper/Item.php +++ b/library/templates/Intonation/Library/View/Wrapper/Item.php @@ -113,14 +113,13 @@ class Intonation_Library_View_Wrapper_Item extends Intonation_Library_View_Wrapp public function getBadges() { - $badges [] = $this->_getSectionBadge(); - $badges [] = $this->_getEmplacementBadge(); - $badges [] = $this->_getCoteBadge(); - $badges [] = $this->_getDateRetourBadge(); - $badges [] = $this->_getReservationsBadge(); - - foreach( $this->getDatasItemsBadges() as $item_badge) - $badges[] = $item_badge; + $badges = [$this->_getSectionBadge(), + $this->_getEmplacementBadge(), + $this->_getCoteBadge(), + $this->_getBrowseShelfBadge(), + $this->_getDateRetourBadge(), + $this->_getReservationsBadge(), + ...$this->getDatasItemsBadges()]; return $this->_view->badgeGroup(array_filter($badges), $this); } @@ -152,11 +151,34 @@ class Intonation_Library_View_Wrapper_Item extends Intonation_Library_View_Wrapp $action ->setImage($this->getSecondaryIco()) - ->setText($action->getAttrib('text-hold', $action->getText())); + ->setText($action->getAttrib('text-hold', + $action->getText())); + return [$action]; } + protected function _getBrowseShelfBadge() : ?Intonation_Library_Badge { + if ( ! Class_Profil_ItemsSettings::current()->isItemsShelfEnabled()) + return null; + + if ( ! $this->_model->getShelfKey()) + return null; + + return (new Intonation_Library_Badge) + ->setTag('a') + ->setUrl(Class_Url::relative(['controller' => 'recherche', + 'action' => 'shelf', + 'item_id' => $this->_model->getId()])) + ->setClass('browse_shelf') + ->setText($this->_('Parcourir l\'étagère')) + ->setImage($this->_view->renderIcon('class fas fa-glasses')) + ->setTitle($this->_('Parcourir l\'étagère de la bibliothèque %s', + $this->_model->getBibLibelle())) + ->setOnClick('$(this).item_shelf(event);'); + } + + public function getEmbedMedia() { return ''; } @@ -190,7 +212,6 @@ class Intonation_Library_View_Wrapper_Item extends Intonation_Library_View_Wrapp return null; return (new Intonation_Library_Badge) - ->setTag('span') ->setClass('badge-secondary badge-emplacement') ->setImage($this->getIco('place', 'library')) ->setText(Class_CodifEmplacement::getLabel($this->_model->getEmplacement())) @@ -216,7 +237,6 @@ class Intonation_Library_View_Wrapper_Item extends Intonation_Library_View_Wrapp return null; return (new Intonation_Library_Badge) - ->setTag('span') ->setClass('badge-warning') ->setImage($this->getIco('return-date', 'library')) ->setText($this->_model->getDateRetour()) @@ -230,7 +250,6 @@ class Intonation_Library_View_Wrapper_Item extends Intonation_Library_View_Wrapp return null; return (new Intonation_Library_Badge) - ->setTag('span') ->setClass('item_hold_rank badge-warning') ->setImage($this->getIco('hold', 'library')) ->setText($this->_plural($this->_getCurrentHoldsCount(), diff --git a/library/templates/Intonation/Library/View/Wrapper/Library/RichContent/Team.php b/library/templates/Intonation/Library/View/Wrapper/Library/RichContent/Team.php index 792194c36ea392dd6ef459a5c7ab3db11bf8f58a..93c3547a914792229f5e328875283234541e4795 100644 --- a/library/templates/Intonation/Library/View/Wrapper/Library/RichContent/Team.php +++ b/library/templates/Intonation/Library/View/Wrapper/Library/RichContent/Team.php @@ -71,7 +71,9 @@ class Intonation_Library_View_Wrapper_Library_RichContent_Team extends Intonatio return $this->_view->renderingVertical($wrapped); }; - return $this->_view->renderMultipleCarousel(new Storm_Collection($pros), $callback); + return $this->_view->renderMultipleCarousel(new Storm_Collection($pros), + $callback, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(5)); } diff --git a/library/templates/Intonation/Library/View/Wrapper/Record/RichContent/Related.php b/library/templates/Intonation/Library/View/Wrapper/Record/RichContent/Related.php index 19f045bdcbe76180a4a49070f1a22cfdeac21f83..859f7bb42103a4ad6bc19c7a31b169a90544b78a 100644 --- a/library/templates/Intonation/Library/View/Wrapper/Record/RichContent/Related.php +++ b/library/templates/Intonation/Library/View/Wrapper/Record/RichContent/Related.php @@ -113,13 +113,15 @@ class Intonation_Library_View_Wrapper_Record_RichContent_RelatedForRecord $html [] = $view->div(['class' => 'col-12 mt-3'], $view->tag('h2', $this->_('Les documents de la même série')) . $view->renderMultipleCarousel(new Storm_Collection($same_series), - $this->_callback)); + $this->_callback, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(5))); if ($like = $model->getNoticesSimilaires()) $html [] = $view->div(['class' => 'col-12 mt-3'], $view->tag('h2', $this->_('Les similaires')) . $view->renderMultipleCarousel(new Storm_Collection($like), - $this->_callback)); + $this->_callback, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(5))); return implode($html); } @@ -147,7 +149,8 @@ class Intonation_Library_View_Wrapper_Record_RichContent_RelatedForWork if ($editions = $model->getNoticesSameWork()) $html [] = $view->div(['class' => 'col-12 mt-3'], $view->renderMultipleCarousel(new Storm_Collection($editions), - $this->_callback)); + $this->_callback, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(5))); return implode($html); } diff --git a/library/templates/Intonation/Library/View/Wrapper/User/RichContent/Settings.php b/library/templates/Intonation/Library/View/Wrapper/User/RichContent/Settings.php index 30edcfd2b133f71b10c795304f4a8f83866562c4..f9df3502c2722d03122eebd909686aacae2bf46a 100644 --- a/library/templates/Intonation/Library/View/Wrapper/User/RichContent/Settings.php +++ b/library/templates/Intonation/Library/View/Wrapper/User/RichContent/Settings.php @@ -109,7 +109,8 @@ class Intonation_Library_View_Wrapper_User_RichContent_Settings extends Intonati return $this->_view->renderingVertical($wrapped); }; - return $this->_view->renderMultipleCarousel(new Storm_Collection($cards), $callback); + return $this->_view->renderMultipleCarousel(new Storm_Collection($cards), $callback, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(5)); } diff --git a/library/templates/Intonation/Library/Widget/Carousel/Settings.php b/library/templates/Intonation/Library/Widget/Carousel/Settings.php new file mode 100644 index 0000000000000000000000000000000000000000..dc8d09045ce69564d327199921d47c5d7ba4aa9a --- /dev/null +++ b/library/templates/Intonation/Library/Widget/Carousel/Settings.php @@ -0,0 +1,82 @@ +<?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 Intonation_Library_Widget_Carousel_Settings { + + CONST CAROUSEL_PAGE_ACTIVE = 'active'; + + protected int $_active_page = 0; + protected int $_columns = 1; + protected string $_classes = ''; + + + public function getActivePage() : int { + return $this->_active_page; + } + + + public function setActivePage(int $page) : self { + $this->_active_page = $page; + return $this; + } + + + public function getColumns() : int { + return $this->_columns; + } + + + public function setColumns(int $columns) : self { + $this->_columns = $columns; + return $this; + } + + + public function initDefaultsFor(string $layout) : self { + if ($layout === Intonation_Library_Widget_Carousel_Definition::MULTIPLE_CAROUSEL) + $this->setColumns(3); + + if ($layout === Intonation_Library_Widget_Carousel_Definition::MULTIPLE_CAROUSEL_PLUS) + $this->setColumns(5); + + return $this; + } + + + public function getCssClassesForPosition(string $classes, int $position) : string { + if ( $position == $this->_active_page) + $classes .= ' ' . static::CAROUSEL_PAGE_ACTIVE; + + return $classes; + } + + + public function setClasses(string $classes) : self { + $this->_classes = $classes; + return $this; + } + + + public function getClasses() : string { + return $this->_classes; + } +} diff --git a/library/templates/Intonation/Library/Widget/Carousel/View.php b/library/templates/Intonation/Library/Widget/Carousel/View.php index 8c077aae298724326bc308c2f93a06f60f019cef..1b96e8f6c1a30dcdfd3db2f6d0bf8a04887e806a 100644 --- a/library/templates/Intonation/Library/Widget/Carousel/View.php +++ b/library/templates/Intonation/Library/Widget/Carousel/View.php @@ -218,7 +218,7 @@ abstract class Intonation_Library_Widget_Carousel_View extends Zendafi_View_Help return isset(static::$_helper_by_layout[$layout]) ? static::$_helper_by_layout[$layout] - : Intonation_View_RenderMultipleCarousel::class; + : Intonation_View_RenderTruncateList::class; } @@ -239,21 +239,23 @@ abstract class Intonation_Library_Widget_Carousel_View extends Zendafi_View_Help Intonation_Library_Widget_Carousel_Definition::GRID])) $this->_layout_helper->setIdModule($this->_settings->getIdForHtml()); - if ($layout === Intonation_Library_Widget_Carousel_Definition::MULTIPLE_CAROUSEL) - $this->_layout_helper->setNumberOfColumns(3); - return $this->_layout_helper; } protected function _renderLayout($layout, $elements, $content_callback) { - $layout_helper = $this->_getLayoutHelper((string) $layout); - $helper_func = array_reverse(explode('_', get_class($layout_helper)))[0]; - return call_user_func_array([$layout_helper, - $helper_func], + $args = [new Storm_Collection($elements), + $content_callback]; + + if ( $this->isLayoutCarousel((string) $layout)) + $args [] = (new Intonation_Library_Widget_Carousel_Settings)->initDefaultsFor($layout); + + $helper_class = $this->_getLayoutHelper((string) $layout); + $helper_function = array_reverse(explode('_', get_class($helper_class)))[0]; - [new Storm_Collection($elements), - $content_callback]); + return call_user_func_array([$helper_class, + $helper_function], + $args); } @@ -411,9 +413,10 @@ abstract class Intonation_Library_Widget_Carousel_View extends Zendafi_View_Help } - public function isLayoutCarousel() : bool { + public function isLayoutCarousel(string $layout = '') : bool { + $layout = $layout ? $layout : $this->_settings->getLayout(); return - array_key_exists($this->_settings->getLayout(), + array_key_exists($layout, (new Intonation_Library_Widget_Carousel_Definition)->getCarouselLayouts()); } diff --git a/library/templates/Intonation/View/Abonne/HistoryLoansList.php b/library/templates/Intonation/View/Abonne/HistoryLoansList.php index a8da40b9d6cd2df1bb67053d50131234c7aa8279..c23b32bb4e463ea5ea98fc10ca17837b44d06c5d 100644 --- a/library/templates/Intonation/View/Abonne/HistoryLoansList.php +++ b/library/templates/Intonation/View/Abonne/HistoryLoansList.php @@ -30,6 +30,8 @@ class Intonation_View_Abonne_HistoryLoansList extends Intonation_View_Abonne_Loa protected function _renderList($collection, $actions) { return Intonation_View_RenderTruncateList::AJAX_SIZE < $collection->count() ? $this->view->renderTruncateList($collection, null) - : $this->view->renderMultipleCarousel($collection, null, 3); + : $this->view->renderMultipleCarousel($collection, + null, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(3)); } } diff --git a/library/templates/Intonation/View/Abstract/Carousel.php b/library/templates/Intonation/View/Abstract/Carousel.php index 5e3775e09a8632742996534911ef582c119f746c..217fbac988340869861be392d41f3e5dc7a69568 100644 --- a/library/templates/Intonation/View/Abstract/Carousel.php +++ b/library/templates/Intonation/View/Abstract/Carousel.php @@ -20,18 +20,23 @@ */ -abstract class Intonation_View_Abstract_Carousel extends Intonation_View_Abstract_Layout { +abstract class Intonation_View_Abstract_Carousel + extends Intonation_View_Abstract_Layout { - protected function _renderCarousel($collection, $callback) { + protected Intonation_Library_Widget_Carousel_Settings $_settings; + + + protected function _renderCarousel(Storm_Collection $collection, + ?Callable $callback, + Intonation_Library_Widget_Carousel_Settings $settings) { if ($collection->isEmpty()) return ''; + $this->_settings = $settings; + $callback = $callback ? $callback - : (function($item) - { - return $this->view->renderingVertical($item); - }); + : (fn($item) => $this->view->renderingVertical($item)); $id = 'carousel_' . uniqid(); @@ -74,18 +79,19 @@ $("#%1$s").on("slid.bs.carousel", } - protected function _indicators($count, $id) { + protected function _indicators(int $count, string $id) : string { if (1 >= $count) return ''; $lis = []; for ($i = 0; $i < $count; $i++) - $lis [] = $this->_tag('li', - '', - ['class' => 'bg-dark ' . (($i == 0) ? 'active' : ''), - 'data-target' => '#' . $id, - 'data-slide-to' => $i]); + $lis [] = + $this->_tag('li', + '', + ['class' => $this->_settings->getCssClassesForPosition('bg-dark', $i), + 'data-target' => '#' . $id, + 'data-slide-to' => $i]); return $this->_tag('ol', implode($lis), @@ -93,14 +99,20 @@ $("#%1$s").on("slid.bs.carousel", } - protected function _carouselInner($collection, $id, $callback) { - $html = $collection->injectInto([], function($html, $element) use ($callback) - { - $html [] = $this->_tag('div', - $callback($element), - ['class' => 'carousel-item'. (0 == count($html) ? ' active' : '')]); - return $html; - }); + protected function _carouselInner(Storm_Collection $collection, + string $id, + Callable $callback) : string { + $html = $collection + ->injectInto([], + function($html, $element) use ($callback) + { + $html [] = + $this->_tag('div', + $callback($element), + ['class' => ($this->_settings + ->getCssClassesForPosition('carousel-item', count($html)))]); + return $html; + }); return $this->_tag('div', implode($html), diff --git a/library/templates/Intonation/View/Author/RenderCollaborations.php b/library/templates/Intonation/View/Author/RenderCollaborations.php index 1b4756253283503fb5d95622e2d78eefe215b055..e7db5d43314f83df3b430eadec21fec1e8aa693d 100644 --- a/library/templates/Intonation/View/Author/RenderCollaborations.php +++ b/library/templates/Intonation/View/Author/RenderCollaborations.php @@ -27,7 +27,8 @@ class Intonation_View_Author_RenderCollaborations extends ZendAfi_View_Helper_Ba }; return ($content = $this->view->renderMultipleCarousel(new Storm_Collection($author->getAssociatedAuthors()), - $callback)) + $callback, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(5))) ? $this->_tag('h3', $this->_('Auteurs associés')) . $content : ''; } diff --git a/library/templates/Intonation/View/Author/RenderRecords.php b/library/templates/Intonation/View/Author/RenderRecords.php index 0e06c64cbfd4023b4f8f7fa193f2a8f5a12b2b1a..50760f3c4d34af64dec487f24c10f25ee0d74aad 100644 --- a/library/templates/Intonation/View/Author/RenderRecords.php +++ b/library/templates/Intonation/View/Author/RenderRecords.php @@ -48,10 +48,10 @@ class Intonation_View_Author_RenderRecords extends ZendAfi_View_Helper_BaseHelpe $elements = Class_Template::current()->newWrappers($records, $this->view); - $records = $this->view->renderMultipleCarousel($elements, function($record) - { - return $this->view->renderingOnlyImage($record); - }); + $records = + $this->view->renderMultipleCarousel($elements, + fn($record) => $this->view->renderingOnlyImage($record), + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(5)); return $this->_div(['class' => 'col-12'], $header . $records); } diff --git a/library/templates/Intonation/View/Author/RenderYoutubeChan.php b/library/templates/Intonation/View/Author/RenderYoutubeChan.php index 39c5dbf5f92b1ea450e32f6225f92d9bb1eed048..ba78e22ef4dded8f5da0dabd3bc786f22c7cf4b0 100644 --- a/library/templates/Intonation/View/Author/RenderYoutubeChan.php +++ b/library/templates/Intonation/View/Author/RenderYoutubeChan.php @@ -49,6 +49,7 @@ class Intonation_View_Author_RenderYoutubeChan extends ZendAfi_View_Helper_BaseH return $this->_tag('h3', $this->_('Chaîne Youtube')) . $this->view->layoutCarousel(new Storm_Collection($items), - $callback); + $callback, + new Intonation_Library_Widget_Carousel_Settings); } } diff --git a/library/templates/Intonation/View/RenderInterviews.php b/library/templates/Intonation/View/RenderInterviews.php index 03089f57cdba91e8fc89306df75e51680392c541..e7982c081a118c966bec8446a535ab856e6118bc 100644 --- a/library/templates/Intonation/View/RenderInterviews.php +++ b/library/templates/Intonation/View/RenderInterviews.php @@ -43,6 +43,9 @@ class Intonation_View_RenderInterviews extends ZendAfi_View_Helper_BaseHelper { $interview->getDescription()))); }; - return $this->view->layoutCarousel($interviews, $callback); + return + $this->view->layoutCarousel($interviews, + $callback, + new Intonation_Library_Widget_Carousel_Settings); } } diff --git a/library/templates/Intonation/View/RenderMultipleCarousel.php b/library/templates/Intonation/View/RenderMultipleCarousel.php index bb156d558b891eb418349688e3394491d6476d88..8a486f7fdabb23ce589719db6c2c977e42a84386 100644 --- a/library/templates/Intonation/View/RenderMultipleCarousel.php +++ b/library/templates/Intonation/View/RenderMultipleCarousel.php @@ -20,28 +20,19 @@ */ -class Intonation_View_RenderMultipleCarousel extends Intonation_View_Abstract_Carousel { +class Intonation_View_RenderMultipleCarousel + extends Intonation_View_Abstract_Carousel { - protected $_columns = 5; - - public function renderMultipleCarousel($collection, $callback = null, $number_of_columns = '') { - $this->setNumberOfColumns($number_of_columns); - return $this->_renderCarousel($collection, $callback); - } - - - public function setNumberOfColumns($columns) { - if (!$columns) - return $this; - - $this->_columns = $columns; - return $this; + public function renderMultipleCarousel($collection, + $callback = null, + Intonation_Library_Widget_Carousel_Settings $settings) { + return $this->_renderCarousel($collection, $callback, $settings); } protected function _numberOfPages($collection) { - return ceil($collection->count() / $this->_columns); + return ceil($collection->count() / $this->_settings->getColumns()); } @@ -55,18 +46,24 @@ class Intonation_View_RenderMultipleCarousel extends Intonation_View_Abstract_Ca } - protected function _carouselInner($collection, $id, $callback) { - $cards = array_filter($collection->injectInto([], function($html, $element) use ($callback) - { - $html [] = $callback($element); - return $html; - })); - - return parent::_carouselInner($this->_cardLayout($cards), $id, fn($element) => $element); + protected function _carouselInner(Storm_Collection $collection, + string $id, + Callable $callback) : string { + $cards = + array_filter($collection->injectInto([], + function($html, $element) use ($callback) + { + $html [] = $callback($element); + return $html; + })); + + return parent::_carouselInner($this->_cardLayout($cards), + $id, + fn($element) => $element); } protected function _cardLayout($cards) { - return $this->view->renderCardLayout($cards, $this->_columns); + return $this->view->renderCardLayout($cards, $this->_settings->getColumns()); } -} \ No newline at end of file +} diff --git a/library/templates/Intonation/View/RenderRecord/RenderItems.php b/library/templates/Intonation/View/RenderRecord/RenderItems.php index 44fc6b6d4443436cbcc1210bb88ec58f2e208da9..d2a186796ffa41121e74faf7a10af2538a395bfa 100644 --- a/library/templates/Intonation/View/RenderRecord/RenderItems.php +++ b/library/templates/Intonation/View/RenderRecord/RenderItems.php @@ -22,11 +22,11 @@ class Intonation_View_RenderRecord_RenderItems extends ZendAfi_View_Helper_BaseHelper { - protected $_should_display_map_cache, $_should_use_ILS_items_threshold_cache, - $_should_paginate_cache; + $_should_paginate_cache, + $_should_display_shelf_cache; public function renderRecord_RenderItems(array $items, array $same_work = []) : string { @@ -41,15 +41,46 @@ class Intonation_View_RenderRecord_RenderItems extends ZendAfi_View_Helper_BaseH } + public function renderHeadScriptsOn($script_loader) { + if ( !$this->_shouldDisplayShelf()) + return $this; + + Class_ScriptLoader::getInstance() + ->addScript(Class_Url::relative('/library/templates/Intonation/Assets/js/item_shelf/item_shelf.js')); + + return $this; + } + + protected function _renderItems(array $items, array $same_work) : string { - $html = [ $this->_hookForMoreHtml($items) ]; + $html = [$this->_renderShelf(), + $this->_hookForMoreHtml($items) ]; return ($html = $this->_renderItemsByStrategy($items, $same_work, $html)) - ? $this->view->grid(implode($html)) + ? $this->view->grid($html) : ''; } + protected function _renderShelf() : string { + if ( !$this->_shouldDisplayShelf()) + return ''; + + $this->renderHeadScriptsOn(Class_ScriptLoader::getInstance()); + return $this->_div(['id' => 'items_shelf', + 'class' => 'items_shelf']); + } + + + protected function _shouldDisplayShelf() : bool { + if ( isset($this->_should_display_shelf_cache)) + return $this->_should_display_shelf_cache; + + return $this->_should_display_shelf_cache = + Class_Profil_ItemsSettings::current()->isItemsShelfEnabled(); + } + + protected function _renderItemsByStrategy(array $items, array $same_work, array $html) : array { @@ -473,4 +504,4 @@ class Intonation_View_RenderRecord_RenderItemsStrategyMapAndILS extends protected function _getOsmItemWrapper() : string { return Intonation_Library_View_Wrapper_ItemForOsm::class; } -} \ No newline at end of file +} diff --git a/library/templates/Intonation/View/Search/History.php b/library/templates/Intonation/View/Search/History.php index 41d75a1d9d2114916a17ff2a7338c5bb50933e14..0ee71fa3d1e0da204c08aad10b59d79f8da566ff 100644 --- a/library/templates/Intonation/View/Search/History.php +++ b/library/templates/Intonation/View/Search/History.php @@ -65,7 +65,9 @@ class Intonation_View_Search_History extends ZendAfi_View_Helper_BaseHelper { $html = [$this->view->div(['class' => 'col-12'], $this->view->renderCollectionActions($actions)), $this->view->div(['class' => 'col-12 mt-3'], - $this->view->renderMultipleCarousel(new Storm_Collection($history), $callback))]; + $this->view->renderMultipleCarousel(new Storm_Collection($history), + $callback, + (new Intonation_Library_Widget_Carousel_Settings)->setColumns(5)))]; $html = $this->view->grid(implode($html)); diff --git a/public/opac/js/ajaxifyPaginatedList/ajaxifyPaginatedList.js b/public/opac/js/ajaxifyPaginatedList/ajaxifyPaginatedList.js index 0089b3aedaeb47b5c0cc6008bc32f0a5f5934b04..39adb27c9239fe8b4b32b153cab840be03752960 100644 --- a/public/opac/js/ajaxifyPaginatedList/ajaxifyPaginatedList.js +++ b/public/opac/js/ajaxifyPaginatedList/ajaxifyPaginatedList.js @@ -56,7 +56,7 @@ if (undefined != $.fn.openStreetMap) widget.openStreetMap(); - + initializePopups(); setupAnchorsTarget(); }; diff --git a/scripts/index_items_shelf_key.php b/scripts/index_items_shelf_key.php new file mode 100644 index 0000000000000000000000000000000000000000..9cdfd1f3a602c352c2c561700832816abc2e89cb --- /dev/null +++ b/scripts/index_items_shelf_key.php @@ -0,0 +1,4 @@ +<?php +require('includes.php'); +Bokeh_Engine::getInstance()->warmUp(); +(new Class_Migration_IndexItemsShelfKey)->run(); \ No newline at end of file diff --git a/tests/application/modules/opac/controllers/RechercheControllerTest.php b/tests/application/modules/opac/controllers/RechercheControllerTest.php index 4f5217995b132c17a324c49e935377d95b39a51a..fba973f5b4c96ed7410ca1b4518b2900dcc0f7b0 100644 --- a/tests/application/modules/opac/controllers/RechercheControllerTest.php +++ b/tests/application/modules/opac/controllers/RechercheControllerTest.php @@ -1041,7 +1041,6 @@ class RechercheControllerViewNoticeClefAlphaTest /** @test */ public function resultatSuivantShouldLinkToNavigationSuivant() { - xdebug_break(); $this->assertXPathContentContains('//div//a[contains(@href, "/recherche/viewnotice/expressionRecherche/Millenium/clef/TESTINGALPHAKEY---101/id/345/navigation/suivant")]', 'Document suivant'); } diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php index 5e8e8e334a5988951244bc307bc0c55bac97e114..f7ed74271d72dd052d98527defc1839228bbb5ff 100644 --- a/tests/db/UpgradeDBTest.php +++ b/tests/db/UpgradeDBTest.php @@ -27,7 +27,7 @@ abstract class UpgradeDBTestCase extends PHPUnit_Framework_TestCase { $this->_movePatchLevelTo(min($patch_level, $this->_getPatchLevel() - 1)); $this->prepare(); $migrator = (new Class_Migration_ScriptPatchs()); - $migrator->setEcho(function(){}); + $migrator->setEchoFunction(fn() => null); $migrator->runTo($this->_getPatchLevel()); } @@ -4630,3 +4630,38 @@ class UpgradeDB_433_Test extends UpgradeDBTestCase { $this->assertFieldType('codif_type_doc', 'label_zotero', 'varchar(255)'); } } + + + + +class UpgradeDB_434_Test extends UpgradeDBTestCase { + + public function prepare() { + $this->silentQuery("alter table exemplaires drop column shelf_key"); + $this->silentQuery("alter table exemplaires drop column shelf_key_update_date"); + } + + + /** @test */ + public function tableExemplairesShouldHaveColumnShelfKeyWithTypeVarchar255() { + $this->assertFieldType('exemplaires', 'shelf_key', 'varchar(255)'); + } + + + /** @test */ + public function shelfKeyDefaultShouldBeNull() { + $this->assertFieldNullable('exemplaires', 'shelf_key'); + } + + + /** @test */ + public function tableExemplairesShouldHaveColumnShelfKeyUpdateDateWithTypeTimestamp() { + $this->assertFieldType('exemplaires', 'shelf_key_update_date', 'timestamp'); + } + + + /** @test */ + public function shelfKeyUpdateDateDefaultShouldBeNull() { + $this->assertFieldNullable('exemplaires', 'shelf_key_update_date'); + } +} \ No newline at end of file diff --git a/tests/js/ItemShelf.php b/tests/js/ItemShelf.php new file mode 100644 index 0000000000000000000000000000000000000000..af51ac915f098e0aaa75e9b1468c0ea98c6ef96f --- /dev/null +++ b/tests/js/ItemShelf.php @@ -0,0 +1,25 @@ +<?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 ItemShelf extends BrowserTest { + protected $_test_path = 'library/templates/Intonation/Assets/js/item_shelf/item_shelf_tests.html'; +} diff --git a/tests/library/Class/BatchTest.php b/tests/library/Class/BatchTest.php index ad75d4484045dad1f3dbaa39d115c6e13d3d2648..142a7ed7268e3b9a15cf0dcf8199525874099733 100644 --- a/tests/library/Class/BatchTest.php +++ b/tests/library/Class/BatchTest.php @@ -123,12 +123,13 @@ class BatchLoaderWithoutRessourcesNumeriquesTest extends ModelTestCase { class BatchIndexRessourcesNumeriquesTest extends ModelTestCase { public function setUp() { + parent::setUp(); $album = $this->fixture('Class_Album', ['id' => 1, 'titre' => 'Mon Album', 'status' => Class_Album::STATUS_VALIDATED]); - Class_Notice::beVolatile(); Storm_Cache::beVolatile(); + $this->cache = new Storm_Cache(); $this->cache->save('some', 'data'); $this->assertEquals('some', $this->cache->load('data')); diff --git a/tests/library/Class/Cosmogramme/Integration/PhaseItemsShelfKeyGenerationTest.php b/tests/library/Class/Cosmogramme/Integration/PhaseItemsShelfKeyGenerationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3491e5975b8a0d0e73168bc911687d6c07297ab1 --- /dev/null +++ b/tests/library/Class/Cosmogramme/Integration/PhaseItemsShelfKeyGenerationTest.php @@ -0,0 +1,202 @@ +<?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 + */ + + +abstract class PhaseItemsShelfKeyGenerationTestCase extends Class_Cosmogramme_Integration_PhaseTestCase { + + protected bool $_build_result_to_update_done = false; + protected bool $_build_result_to_init_done = false; + + + public function setUp() { + parent::setUp(); + + Class_Cosmogramme_Integration_PhaseAbstract::shouldThrowError(true); + Class_CosmoVar::setValueOf('shelf_key_update_date', '2022-05-31 10:45:12'); + Class_Migration_IndexItemsShelfKey::setTimeSource(new TimeSourceForTest('2022-06-01 03:07:10')); + + $count = 3; + + $sql = $this + ->mock() + ->beStrict() + + ->whenCalled('fetchAllByColumn') + ->with("select count(exemplaires.id) from exemplaires where exemplaires.cote > '' AND ( exemplaires.shelf_key IS NULL OR exemplaires.shelf_key = '' OR ( exemplaires.shelf_key_update_date > '2022-05-31 10:45:12' AND exemplaires.shelf_key_update_date < '2022-06-01 03:07:10' ))") + ->answers([$count]) + + ->whenCalled('fetchAll') + ->with("select exemplaires.id, exemplaires.id_notice, exemplaires.cote, notices.clef_chapeau, notices.tome_alpha, notices.clef_alpha from exemplaires inner join notices on exemplaires.id_notice = notices.id_notice where exemplaires.cote > '' AND ( exemplaires.shelf_key IS NULL OR exemplaires.shelf_key = '' OR ( exemplaires.shelf_key_update_date > '2022-05-31 10:45:12' AND exemplaires.shelf_key_update_date < '2022-06-01 03:07:10' )) limit 5000") + ->willDo(fn() => $this->_buildResultToUpdate($count)) + + ->whenCalled('execute') + ->with('update exemplaires set shelf_key = (CASE WHEN (id = "1") THEN "0AMT_000R_0GER_0740_0001_0698_BOOK-OF-_BOOK_BOOK-OF-_0001" WHEN (id = "2") THEN "0AMT_000R_0GER_0740_0001_0698_BOOK-OF-_BOOK_BOOK-OF-_0002" WHEN (id = "3") THEN "0AMT_000R_0GER_0740_0001_0698_BOOK-OF-_BOOK_BOOK-OF-_0003" ELSE shelf_key END), shelf_key_update_date = \'2022-06-01 03:07:10\' WHERE id in (1,2,3)') + ->answers(true) + + ->whenCalled('execute') + ->with('update exemplaires set shelf_key = (CASE WHEN (id = "1") THEN "0AMT_000R_0GER_0740_0001_0698_BOOK-OF-_BOOK_BOOK-OF-_0001" WHEN (id = "2") THEN "0AMT_000R_0GER_0740_0001_0698_BOOK-OF-_BOOK_BOOK-OF-_0002" ELSE shelf_key END), shelf_key_update_date = \'2022-06-01 03:07:10\' WHERE id in (1,2,3)') + ->answers(true); + + Zend_Registry::set('sql', $sql); + + $this->_phase = $this->_buildPhase('ItemsShelfKeyGeneration') + ->noDbReset() + ->run(); + } + + + public function tearDown() { + Class_Cosmogramme_Integration_PhaseAbstract::shouldThrowError(false); + parent::tearDown(); + } + + + protected function _buildResultToUpdate(int $count) : array { + if ( $this->_build_result_to_update_done) + return []; + + $this->_build_result_to_update_done = true; + return $this->_buildResult($count); + } + + + protected function _buildResultToInit(int $count) : array { + if ( $this->_build_result_to_init_done) + return []; + + $this->_build_result_to_init_done = true; + return $this->_buildResult($count); + } + + + protected function _buildResult(int $count) : array { + $result = []; + for ($i = 1; $i <= $count ; $i++) + $result [] = + ['id' => $i, + 'id_notice' => $i, + 'cote' => 'AMT R GER 740.1 698', + 'clef_chapeau' => 'BOOK-OF-SOULS', + 'tome_alpha' => 'BOOK_1', + 'clef_alpha' => 'BOOK-OF-SOULS_1_2_3']; + + return $result; + } +} + + + + +class PhaseItemsShelfKeyGenerationBadPreviousPhaseTest extends PhaseItemsShelfKeyGenerationTestCase { + + protected function _getPreviousPhase() { + return new Class_Cosmogramme_Integration_Phase(7); + } + + + /** @test */ + public function shouldNotChangePhase() { + $this->assertTrue($this->_phase->isId(7)); + } +} + + + + +class PhaseItemsShelfKeyGenerationRunTest extends PhaseItemsShelfKeyGenerationTestCase { + + protected function _getPreviousPhase() { + return (new Class_Cosmogramme_Integration_Phase(7.3)) + ->beCron(); + } + + + /** @test */ + public function phaseShouldBeSevenDotThree() { + $this->assertTrue($this->_phase->isId(7.3)); + } + + + /** @test */ + public function logShouldContainsUIEu() { + $this->assertEquals(' ===== Début de la phase d\'indexation des clés d\'étagères des exemplaires ===== + + ===== Indexation des clés ===== + + Nombre de clés à indexer : 3 + + page de 3 exemplaires : 1/1 + en 0s + + [OK] + + ===== Indexation des clés traitée en 0s ===== + + + ===== Fin de la phase d\'indexation des clés d\'étagères. Durée : 0s ===== + + +', $this->_log_content); + } +} + + + + +class PhaseItemsShelfKeyGenerationRunWithMysqlLoopTest extends PhaseItemsShelfKeyGenerationTestCase { + + protected function _getPreviousPhase() { + return (new Class_Cosmogramme_Integration_Phase(7.3)) + ->beCron(); + } + + + /** @test */ + public function phaseShouldBeSevenDotThree() { + $this->assertTrue($this->_phase->isId(7.3)); + } + + + protected function _buildResultToUpdate(int $count) : array { + return $this->_buildResult(3); + } + + + /** @test */ + public function logShouldContainsUIEu() { + $this->assertEquals(' ===== Début de la phase d\'indexation des clés d\'étagères des exemplaires ===== + + ===== Indexation des clés ===== + + Nombre de clés à indexer : 3 + + page de 3 exemplaires : 1/1 + en 0s + + ===== Indexation des clés stopée. ===== + + + ===== Fin de la phase d\'indexation des clés d\'étagères. Durée : 0s ===== + + +', $this->_log_content); + } +} \ No newline at end of file diff --git a/tests/library/Class/ExemplaireTest.php b/tests/library/Class/ExemplaireTest.php index e681cc3dd25abcd18e3fa710bfdf72032559c074..1e2ac8ddbd9de262d6a8e13c148b77799fd8fbe7 100644 --- a/tests/library/Class/ExemplaireTest.php +++ b/tests/library/Class/ExemplaireTest.php @@ -21,10 +21,6 @@ class Class_ExemplaireTest extends ModelTestCase { - public function setUp() { - parent::setUp(); - - } /** @test */ public function exemplaireIsRessourceNumeriqueShouldNotBeReservable() { @@ -32,6 +28,7 @@ class Class_ExemplaireTest extends ModelTestCase { $this->assertFalse($exemplaire->isReservable()); } + /** @test */ public function exemplaireIsSigbExemplaireAndIsNotReservableShouldNotBeReservable() { $sigb_exemplaire= Storm_Test_ObjectWrapper::mock() @@ -70,4 +67,4 @@ class Class_ExemplaireTest extends ModelTestCase { $this->assertTrue($item->isReservable()); } -} \ No newline at end of file +} diff --git a/tests/library/Class/Migration/UpdateConfigTest.php b/tests/library/Class/Migration/UpdateConfigTest.php index a24991e26b7a938332dd180c55e813982b8d9a25..4bd16268e29988ee99929f642e96013007ca8873 100644 --- a/tests/library/Class/Migration/UpdateConfigTest.php +++ b/tests/library/Class/Migration/UpdateConfigTest.php @@ -21,8 +21,6 @@ class UpdateConfigFileTest extends ModelTestCase { - protected $_storm_default_to_volatile = true; - public function setUp() { parent::setUp(); @@ -49,9 +47,8 @@ class UpdateConfigFileTest extends ModelTestCase { ->answers(true); Class_Migration_UpdateConfig::setFileSystem($file_system); - Class_Migration_UpdateConfig::setEcho(true); - (new Class_Migration_UpdateConfig)->run('bokeh_test_db'); + (new Class_Migration_UpdateConfig)->runWithoutEcho('bokeh_test_db'); } diff --git a/tests/library/Class/Migration/UpdateDatabaseAfterSelectDbTest.php b/tests/library/Class/Migration/UpdateDatabaseAfterSelectDbTest.php index c144936745439f7d286823d16d0a600690fc8d58..d66bd4332611da55dd3640ed743f6a4293af5d7f 100644 --- a/tests/library/Class/Migration/UpdateDatabaseAfterSelectDbTest.php +++ b/tests/library/Class/Migration/UpdateDatabaseAfterSelectDbTest.php @@ -37,8 +37,7 @@ class UpdateDatabaseAfterSelectDbTest extends ModelTestCase { Class_AdminVar::set('STATUS_REPORT_PUSH_URL', 'https://git-bokeh.org'); Class_AdminVar::set('FORCE_HTTPS', '1'); - Class_Migration_UpdateDatabaseAfterSelectDb::setEcho(true); - (new Class_Migration_UpdateDatabaseAfterSelectDb)->run(); + (new Class_Migration_UpdateDatabaseAfterSelectDb)->runWithoutEcho(); } diff --git a/tests/library/Class/MigrationTest.php b/tests/library/Class/MigrationTest.php index c3492169e1e27d7252abde58f96f7f212f077ce4..48941bdcac7a5431ef9f481ea1ea5d4fd7919175 100644 --- a/tests/library/Class/MigrationTest.php +++ b/tests/library/Class/MigrationTest.php @@ -25,8 +25,6 @@ abstract class MigrationTestCase extends ModelTestCase { public function setUp() { parent::setUp(); Storm_Model_Loader::defaultToVolatile(); - Class_Migration_ScriptPatchs::setEcho('none'); - $this->fixture('Class_CosmoVar', ['id' => 'patch_level', 'valeur' => 10 ] ); $this->_old_sql = Zend_Registry::get('sql'); @@ -92,21 +90,23 @@ class Class_MigrationScriptPatchsTest extends MigrationTestCase { /** @test */ public function runPatchShouldUpgradePatchLevelTo12() { - (new Class_Migration_ScriptPatchs())->run(); + (new Class_Migration_ScriptPatchs())->runWithoutEcho(); $this->assertEquals(12,Class_CosmoVar::find('patch_level')->getValeur()); } /** @test */ public function runForcePatchShouldUpgradePatchLevelTo14() { - (new Class_Migration_ScriptPatchs())->run(true); + (new Class_Migration_ScriptPatchs())->runWithoutEcho(true); $this->assertEquals(14, Class_CosmoVar::find('patch_level')->getValeur()); } /** @test */ public function runFromPatchShouldUpgradePatchLevelTo14() { - (new Class_Migration_ScriptPatchs())->runFrom(1, true); + (new Class_Migration_ScriptPatchs()) + ->setEchoFunction(function() {}) + ->runFrom(1, true); $this->assertEquals(14, Class_CosmoVar::find('patch_level')->getValeur()); } } @@ -122,21 +122,21 @@ class MigrationScriptPatchsPhpTest extends MigrationTestCase { /** @test */ public function runPatchShouldUpgradePatchLevelTo12() { - (new Class_Migration_ScriptPatchs())->run(); + (new Class_Migration_ScriptPatchs())->runWithoutEcho(); $this->assertEquals(12, Class_CosmoVar::find('patch_level')->getValeur()); } /** @test */ public function runForcePatchShouldUpgradePatchLevelTo14() { - (new Class_Migration_ScriptPatchs())->run(true); + (new Class_Migration_ScriptPatchs())->runWithoutEcho(true); $this->assertEquals(15, Class_CosmoVar::find('patch_level')->getValeur()); } /** @test */ public function runShouldSaveSha1() { - (new Class_Migration_ScriptPatchs())->run(); + (new Class_Migration_ScriptPatchs())->runWithoutEcho(); $this->assertEquals('bidonquiapaslatetedunchathein', Class_Migration_PatchHash::findFirstBy([])->getValue()); } @@ -144,7 +144,7 @@ class MigrationScriptPatchsPhpTest extends MigrationTestCase { /** @test */ public function runForcedShouldSaveTwoSha1() { - (new Class_Migration_ScriptPatchs())->run(true); + (new Class_Migration_ScriptPatchs())->runWithoutEcho(true); $this->assertEquals(2, Class_Migration_PatchHash::count()); } } @@ -160,8 +160,7 @@ class MigrationFunctionSQLTest extends MigrationTestCase { /** @test */ public function withSqlFunctionShouldRunPatchUntil14() { - (new Class_Migration_ScriptPatchs())->run(false); + (new Class_Migration_ScriptPatchs())->runWithoutEcho(false); $this->assertEquals(14, Class_CosmoVar::find('patch_level')->getValeur()); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/tests/scenarios/ShelfNavigation/ShelfNavigationTest.php b/tests/scenarios/ShelfNavigation/ShelfNavigationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0e5afbf52bdd1b0786b01716d16e7a2c822009ca --- /dev/null +++ b/tests/scenarios/ShelfNavigation/ShelfNavigationTest.php @@ -0,0 +1,476 @@ +<?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 ShelfNavigationShelfKeyTest extends ModelTestCase { + + public function setUp() { + parent::setUp(); + + $this->fixture(Class_Exemplaire::class, + ['id' => 1, + 'cote' => '743.12 BD A']); + + $this->fixture(Class_Exemplaire::class, + ['id' => 11, + 'cote' => 'l\'écureuil volant']); + + $this->fixture(Class_Exemplaire::class, + ['id' => 111, + 'cote' => 'AMT R GER 740.1 698']); + + $this->fixture(Class_Exemplaire::class, + ['id' => 3456780, + 'cote' => 'AMT R GER 740.1 698 I AM LONG']); + + $this->fixture(Class_Notice::class, + ['id' => 1, + 'tome_alpha' => '', + 'clef_alpha' => 'TITREALPHA1', + 'clef_chapeau' => '', + 'exemplaires' => [Class_Exemplaire::find(1), + Class_Exemplaire::find(11)]]); + + $this->fixture(Class_Notice::class, + ['id' => 2, + 'tome_alpha' => '365', + 'clef_alpha' => 'OTHERTITLE', + 'clef_chapeau' => 'KEYCHAPEAU', + 'exemplaires' => [Class_Exemplaire::find(111), + Class_Exemplaire::find(3456780)]]); + } + + + public function getShelfKeyByIdItem() { + return [ + ['0743_0012_00BD_000A_0000_0000_00000000_0000_TITREALP_0001', 1], + ['000L_ECUR_VOLA_0000_0000_0000_00000000_0000_TITREALP_0011', 11], + ['0AMT_000R_0GER_0740_0001_0698_KEYCHAPE_0365_OTHERTIT_0111', 111], + ['0AMT_000R_0GER_0740_0001_0698_KEYCHAPE_0365_OTHERTIT_6780', 3456780], + ]; + } + + + /** + * @dataProvider getShelfKeyByIdItem + * @test + */ + public function forItemIdShouldCreateExpectedShelfKey($shelf_key, $id_item) { + $this->assertEquals($shelf_key, + (Class_Exemplaire::find($id_item) + ->initShelfKey() + ->getShelfKey())); + } +} + + + + +abstract class ShelfNavigationSearchShelfTestCase + extends AbstractControllerTestCase { + + public function setUp() { + parent::setUp(); + + $this->_buildTemplateProfil(['id' => 1, + 'libelle' => 'Shelf templates']); + + (new Class_Profil_ItemsSettings(Class_Profil::find(1))) + ->setSettings(['enable_items_shelf' => 1]); + + $this->fixture(Class_Bib::class, + ['id' => 1, + 'libelle' => 'Annecy']); + + $builder = (new class() { + use Storm_Test_THelpers; + + protected $_id = 0; + + public function buildRecord(int $id_bib, + int $id_emplacement, + int $id_section) { + $this->_id++; + + $exemplaire = + $this->fixture(Class_Exemplaire::class, + ['id' => $this->_id, + 'id_bib' => $id_bib, + 'section' => $id_section, + 'emplacement' => $id_emplacement, + 'cote' => 'COT 743.12 BD 0' . $this->_id + ]) + ->initShelfKey(); + $exemplaire->save(); + + $exemplaire_bis = + $this->fixture(Class_Exemplaire::class, + ['id' => $this->_id + 100, + 'id_bib' => $id_bib, + 'section' => $id_section, + 'emplacement' => $id_emplacement, + 'cote' => 'COT 743.12 BD 0' . $this->_id + ]) + ->initShelfKey(); + $exemplaire_bis->save();; + + $this->fixture(Class_Notice::class, + ['id' => $this->_id, + 'type_doc' => 1, + 'titre_principal' => 'Titre ' . $this->_id, + 'exemplaires' => [ $exemplaire, $exemplaire_bis ] + ]); + } + }); + + for($i = 0; $i < 30; $i++) + $builder->buildRecord(1, 10, 100); + + $before = $builder->buildRecord(1, 9, 99); + $after = $builder->buildRecord(1, 66, 666); + } +} + + + + +class ShelfNavigationSearchShelfInCenterTest + extends ShelfNavigationSearchShelfTestCase { + + public function setUp() { + parent::setUp(); + + $this->dispatch('/recherche/shelf/item_id/15'); + } + + + public function itemTitleAndPosition() { + return [ + ['Titre 13', 1], + ['Titre 14', 2], + ['Titre 15', 3], + ['Titre 16', 4], + ['Titre 17', 5], + ]; + } + + + /** + * @test + * @dataProvider itemTitleAndPosition + **/ + public function activePageInMiddleShouldContainsCardTitleForTitleAtPostion($title, $position) { + $this->assertXPath(sprintf('//div[contains(@class, "carousel-item")][3][contains(@class, "active")]//div[contains(@class, "card_with_overlay")][%s]//div[@class="card-title"][text()="%s"]', + $position, + $title)); + } + + + /** @test */ + public function selectItem15ShouldRenderInDivCardWithOverlayAndShelfCurrentItem() { + $this->assertXPathContentContains('//div[@class="carousel-item active"]//div[contains(@class, "card_with_overlay")][3]/@class', + 'shelf_current_item'); + } + + + /** @test */ + public function onlyOneCardShouldHaveClassShelfCurrentItem() { + $this->assertXPathCount('//div[@class="card_with_overlay shelf_current_item card text-center"]', 1); + } + + + /** @test */ + public function carouselIndicatorsShouldBeOnThirdPage() { + $this->assertXPath('//ol[@class="carousel-indicators my-2 position-relative"]/li[3][contains(@class, "active")]'); + } + + + /** @test */ + public function carouselShouldHaveFivePagesWithBodyPage() { + $this->assertXPathCount('//body//main//div[contains(@class, "carousel-item")]', + 5); + } +} + + + + +class ShelfNavigationSearchShelfAtEndTest extends ShelfNavigationSearchShelfTestCase { + public function setUp() { + parent::setUp(); + + $this->dispatch('/recherche/shelf/item_id/29'); + } + + + public function itemTitleAndPosition() { + return [ + ['Titre 27', 1], + ['Titre 28', 2], + ['Titre 29', 3], + ['Titre 30', 4], + ]; + } + + + /** + * @test + * @dataProvider itemTitleAndPosition + **/ + public function activePageInMiddleShouldContainsCardTitleForTitleAtPostion($title, $position) { + $this->assertXPath(sprintf('//div[contains(@class, "carousel-item")][3][contains(@class, "active")]//div[contains(@class, "card_with_overlay")][%s]//div[contains(@class, "card-title")][text()="%s"]', + $position, + $title)); + } + + + /** @test */ + public function activePageShouldContainsOnlyFourItems() { + $this->assertXPathCount('//div[contains(@class, "carousel-item active")]//div[contains(@class, "card_with_overlay")]', + 4); + } +} + + + + +class ShelfNavigationSearchShelfAtStartTest + extends ShelfNavigationSearchShelfTestCase { + + public function setUp() { + parent::setUp(); + + $this->dispatch('/recherche/shelf/item_id/2'); + } + + + public function itemTitleAndPosition() { + return [ + ['Titre 1', 1], + ['Titre 2', 2], + ['Titre 3', 3], + ['Titre 4', 4], + ['Titre 5', 5], + ]; + } + + /** + * @test + * @dataProvider itemTitleAndPosition + **/ + public function activePageAtStartShouldContainsCardTitleForTitleAtPostion($title, $position) { + $this->assertXPath(sprintf('//div[contains(@class, "carousel-item")][1][contains(@class, "active")]//div[contains(@class, "card_with_overlay")][%s]//div[contains(@class, "card-title")][text()="%s"]', + $position, + $title)); + } + + + /** @test */ + public function pageShouldContainsH2WithEtagereDeLabibliothequeAnnecy() { + $this->assertXPathContentContains('//h2', 'Étagère de la bibliothèque Annecy'); + } +} + + + + +class ShelfNavigationSearchShelfRenderAjaxTest + extends ShelfNavigationSearchShelfTestCase { + + public function setUp() { + parent::setUp(); + + $this->dispatch('/recherche/shelf/item_id/4/render/ajax'); + } + + + /** @test */ + public function carouselShouldRenderWithoutLayout() { + $this->assertNotXPath('//body//main'); + } + + + /** @test */ + public function responseShouldContainsCarousel() { + $this->assertXPathCount('//div[@class="carousel-item active"][1]//div[contains(@class, "card_with_overlay")]', 5, $this->_response->getBody()); + } +} + + + + +class ShelfNavigationSearchErrorTest + extends ShelfNavigationSearchShelfTestCase { + + public function setUp() { + parent::setUp(); + + $this->dispatch('/recherche/shelf/item_id/1004/render/ajax', false); + } + + + /** @test */ + public function responseCodeShouldBe404() { + $this->assertResponseCode(404); + } +} + + + + +class ShelfNavigationWithoutEnableItemsShelfOptionTest + extends ShelfNavigationSearchShelfTestCase { + + public function setUp() { + parent::setUp(); + + (new Class_Profil_ItemsSettings(Class_Profil::find(1)))->setSettings(['enable_items_shelf' => 0]); + + $this->dispatch('/noticeajax/resources/id/4'); + } + + + /** @test */ + public function pageShouldNotContainsLinkBrowseShelf() { + $this->assertNotXPath('//a[contains(@class, "browse-shelf")]'); + } +} + + + + +class ShelfNavigationSearchNoticeAjaxResourcesTest + extends ShelfNavigationSearchShelfTestCase { + + public function setUp() { + parent::setUp(); + + $this->dispatch('/noticeajax/resources/id/4'); + } + + + /** @test */ + public function itemShouldContainsLinkToRechercheShelfItemId104RenderAjax() { + $this->assertXPath('//div[@class="badge-group badge_group badge_group_Intonation_Library_View_Wrapper_ItemWithoutSIGB"]//a[@class="badge_tag browse_shelf text-left badge badge-secondary"][contains(@href, "/recherche/shelf/item_id/4")][contains(@title, "Parcourir")][@onclick="$(this).item_shelf(event);"]'); + } + + + /** @test */ + public function pageShouldContainsDivItemsShelf() { + $this->assertXPath('//div[@class="container-fluid"]/div[@class="row no-gutters"]/div[@id="items_shelf"][@class="items_shelf col-12"]'); + } + + + /** @test */ + public function pageShouldContainsScriptFileItemShelf() { + $this->assertXPath('//script[contains(@src, "/library/templates/Intonation/Assets/js/item_shelf/item_shelf.js")]'); + } +} + + + + +class ShelfNavigationPNBTest extends AbstractControllerTestCase { + + public function setUp() { + parent::setUp(); + + $this->_buildTemplateProfil(['id' => 1, + 'libelle' => 'Shelf templates']); + + $exemplaire = $this->fixture(Class_Exemplaire::class, + ['id' => 1, + 'id_bib' => 1, + 'section' => 1, + 'emplacement' => 1, + 'cote' => 'COT 743.12 BD 001' + ]); + + $this->fixture(Class_Notice::class, + ['id' => 1, + 'type_doc' => 112, + 'titre_principal' => 'Titre PNB', + 'exemplaires' => [ $exemplaire ] + ]); + + $this->dispatch('/noticeajax/resources/id/1'); + } + + + /** @test */ + public function itemShouldNotContainsShelfLink() { + $this->assertNotXPath('//a[contains(@href, "/recherche/shelf/item_id")]'); + } +} + + + + +class ShelfNavigationAdminTest extends Admin_AbstractControllerTestCase { + + public function setUp() { + parent::setUp(); + + $this->_buildTemplateProfil(['id' => 1, + 'libelle' => 'Shelf templates']); + + $this->dispatch('/admin/modulesnotice/exemplaires/id_profil/1'); + } + + + /** @test */ + public function formShouldContainsCheckboxEnableItemsShelf() { + $this->assertXPath('//form//input[@type="checkbox"][@name="enable_items_shelf"]'); + } +} + + + + +class ShelfNavigationWithNoShelKeyTest extends ShelfNavigationSearchShelfTestCase { + + public function setUp() { + parent::setUp(); + + $exemplaire_with_no_shelf_key = + $this->fixture(Class_Exemplaire::class, + ['id' => 789798, + 'id_bib' => 1, + 'section' => 1, + 'emplacement' => 1, + 'cote' => 'COT 743.12 BD 001']); + + $this->fixture(Class_Notice::class, + ['id' => 1781723498, + 'type_doc' => 1, + 'titre_principal' => 'Titre sans shelf_key', + 'exemplaires' => [$exemplaire_with_no_shelf_key] + ]); + + $this->dispatch('/noticeajax/resources/id/1781723498'); + } + + + /** @test */ + public function itemWithNoShelfKeyShouldNotHaveShelfLink() { + $this->assertNotXPath('//a[contains(@href, "/recherche/shelf/item_id/789798")]'); + } +} \ No newline at end of file diff --git a/tests/scenarios/Templates/ChiliMultipleCarouselTest.php b/tests/scenarios/Templates/ChiliMultipleCarouselTest.php index c2c23ead57da45fa0fc99fc77f4d4e5071cc1ba0..76410cbf47f7ad11bca574af827cddad67da23a5 100644 --- a/tests/scenarios/Templates/ChiliMultipleCarouselTest.php +++ b/tests/scenarios/Templates/ChiliMultipleCarouselTest.php @@ -21,8 +21,6 @@ class ChiliMultipleCarouselResponsiveTest extends AbstractControllerTestCase { - protected $_storm_default_to_volatile = true; - public function setUp() { parent::setUp(); @@ -91,7 +89,7 @@ class ChiliMultipleCarouselResponsiveTest extends AbstractControllerTestCase { /** @test */ public function bottenShouldBeInSmActive() { - $this->assertXPathContentContains('//div[contains(@class, "col-12 d-block d-md-none")]//div[contains(@class, "carousel")]//div[@class="carousel-item active"]', - 'Botten', $this->_response->getBody()); + $this->assertXPathContentContains('//div[@class="col-12 d-block d-md-none"]//div[@class="carousel slide"]//div[@class="carousel-item active"]', + 'Botten'); } } diff --git a/tests/scenarios/Templates/ChiliTest.php b/tests/scenarios/Templates/ChiliTest.php index 0f1457586d1c1ee5a5d7ab1375cfebe56b3eb63a..9a6df4e7eee0b0d967d47fbba8d0b8077207ec2d 100644 --- a/tests/scenarios/Templates/ChiliTest.php +++ b/tests/scenarios/Templates/ChiliTest.php @@ -357,7 +357,7 @@ class ChiliTemplateUpdateSettingsTest extends ChiliTemplateTestCase { $chili_settings ->setSettings(serialize($chili_settings_instance->toArray()))->save(); - (new Class_Template_Update)->runWithEcho(true); + (new Class_Template_Update)->runWithoutEcho(); $chili_settings->clearCache(); } diff --git a/tests/scenarios/Templates/MuscleTemplateTest.php b/tests/scenarios/Templates/MuscleTemplateTest.php index cb3a6e08dc7f3d7b5e5fa9f911569612163b6f0f..41f844b8b9b91049072e599e84c89b9dc3d9230e 100644 --- a/tests/scenarios/Templates/MuscleTemplateTest.php +++ b/tests/scenarios/Templates/MuscleTemplateTest.php @@ -418,8 +418,7 @@ class MuscleTemplateUpdateSettingsTest extends MuscleTemplateTestCase { $muscle_settings->setSettings(serialize($muscle_settings_instance->toArray()))->save(); $updader = (new Class_Template_Update); - $updader->setEcho(true); - $updader->run(); + $updader->runWithoutEcho(); $muscle_settings->clearCache(); } diff --git a/tests/scenarios/Templates/TemplatesLibraryTest.php b/tests/scenarios/Templates/TemplatesLibraryTest.php index 8172832853ff4d8d3184bcf986d8b9e5d4e08274..6229c981f4fd2b969b3e8ea1325a1068fedff6f1 100644 --- a/tests/scenarios/Templates/TemplatesLibraryTest.php +++ b/tests/scenarios/Templates/TemplatesLibraryTest.php @@ -631,7 +631,7 @@ class TemplatesLibraryWidgetWithOSMAndLinkToProfileTest extends TemplatesIntonat $settings_insance ->setIntonationIconsMapUtils(['osm_closed_marker' => 'uri /map/were-closed.png']); $settings->setSettings(serialize($settings_insance->toArray()))->save(); - (new Class_Template_Update)->runWithEcho(true); + (new Class_Template_Update)->runWithoutEcho(); $settings->clearCache(); $this->dispatch('/opac/index/index/id_profil/72'); diff --git a/tests/scenarios/Templates/TemplatesSearchItemsTest.php b/tests/scenarios/Templates/TemplatesSearchItemsTest.php index 954782ec404a852bce81ca38d5ee69ef2c598b2f..fe38c886333ce399983145e1f1c670daba99a050 100644 --- a/tests/scenarios/Templates/TemplatesSearchItemsTest.php +++ b/tests/scenarios/Templates/TemplatesSearchItemsTest.php @@ -236,6 +236,18 @@ class TemplateSearchItemsResourceWith30orLessItemsTests public function with30ItemsShouldNotDisplaySearchForm() { $this->assertNotXPath('//input[contains(@class,"zendafi_form_ajax_search")]'); } + + + /** @test */ + public function itemsShelfShouldNotBePresent() { + $this->assertNotXPath('//div[@id="items_shelf"]'); + } + + + /** @test */ + public function itemsShelfScriptShouldNotBePresent() { + $this->assertNotXPath('//script[contains(@src, "item_shelf")]'); + } } @@ -654,6 +666,7 @@ class TemplatesSearchItemsModulesNoticeExemplairesActionTest extends TemplatesTe [ 'input[@id="emplacement"][@type="checkbox"]' ], [ 'input[@id="date_retour"][@type="checkbox"]' ], [ 'input[@id="pagination_threshold"][@type="number"][@value="200"]' ], + [ 'input[@id="enable_items_shelf"][@type="checkbox"]' ], ]; } @@ -1144,4 +1157,4 @@ class TemplatesSearchItems15ItemsPaginationThreshold20AndAvailabilityKohaLimit20 public function jqueryShouldNotBeNotBeLoaded() { $this->assertNotXPath('//script[contains(@src, "jquery")]'); } -} \ No newline at end of file +} diff --git a/tests/scenarios/Templates/TemplatesWidgetCarouselTest.php b/tests/scenarios/Templates/TemplatesWidgetCarouselTest.php index a7a3e0c491f535a9639aec982063e455990e2e9b..db304a2a918e9bb7c811dd14c6a10853536af3d6 100644 --- a/tests/scenarios/Templates/TemplatesWidgetCarouselTest.php +++ b/tests/scenarios/Templates/TemplatesWidgetCarouselTest.php @@ -24,9 +24,7 @@ abstract class TemplatesWidgetCarouselArticlesTestCase extends AbstractControllerTestCase { - protected - $_storm_default_to_volatile = true, - $_loader_article; + protected $_loader_article; public function setUp() { parent::setUp(); @@ -161,8 +159,6 @@ class TemplatesWidgetCarouselLoaderTestTest extends ArticleLoaderGetArticlesByPr class TemplatesWidgetCarouselReviewTest extends AbstractControllerTestCase { - protected $_storm_default_to_volatile = true; - public function setUp() { parent::setUp(); diff --git a/tests/scenarios/Templates/TemplatesWidgetTest.php b/tests/scenarios/Templates/TemplatesWidgetTest.php index 14b28b3085c2f12c28f4b99b1572e6a977430352..c9a6ec0d93db27a6b1e8da58bc80c1ff0934244d 100644 --- a/tests/scenarios/Templates/TemplatesWidgetTest.php +++ b/tests/scenarios/Templates/TemplatesWidgetTest.php @@ -1620,10 +1620,7 @@ class TemplatesWidgetWithTopHighlightLayoutTest extends AbstractTemplatesWidgetW abstract class TemplatesWidgetRenderChiliWallGridLayoutsTestCase extends AbstractControllerTestCase { - protected - $_storm_default_to_volatile = true, - $_layout = ''; - + protected $_layout = ''; public function setUp() { parent::setUp(); @@ -1637,9 +1634,10 @@ abstract class TemplatesWidgetRenderChiliWallGridLayoutsTestCase extends Abstrac Class_Profil::DIV_MAIN, ['layout' => $this->_layout]); - $this->fixture('Class_Notice', - ['id' => 456, - 'titre_principal' => 'Rahan']); + for ($i = 1 ; $i <= 20; $i++) + $this->fixture(Class_Notice::class, + ['id' => $i + 450, + 'titre_principal' => 'Rahan n°' . $i ]); $this->dispatch('/opac/index/index/id_profil/72'); } @@ -1663,6 +1661,20 @@ class TemplatesWidgetRenderGridLayoutTest extends TemplatesWidgetRenderChiliWall public function divClassWallGridMdShouldContainsRahan() { $this->assertXPathContentContains('//div[@class="wall_grid_md d-lg-none"]//div[@class="carousel slide multiple_carousel"]', 'Rahan'); } + + + /** @test */ + public function wallGridMdShouldContainsCardDeckThreeColumns() { + $this->assertXPathCount('//div[@class="wall_grid_md d-lg-none"]//div[@class="carousel slide multiple_carousel"]//div[@class="carousel-item active"]//div[@class="card-deck"]/div[@class="card_with_overlay card"]', + 3); + } + + + /** @test */ + public function wallGridSmShouldContainsCarouselSlideWithOnlyOneColumn() { + $this->assertXPathCount('//div[@class="wall_grid_md d-lg-none"]//div[@class="carousel slide"]//div[@class="carousel-item active"]/div[@class="card_with_overlay card"]', + 1); + } } diff --git a/tests/scripts/SelectDbTest.php b/tests/scripts/SelectDbTest.php index f943fe802a21606d84866c29cc2f324a454e82d0..1c44ba4045cbb91ad9c9825ebe144bfa8105067c 100644 --- a/tests/scripts/SelectDbTest.php +++ b/tests/scripts/SelectDbTest.php @@ -26,8 +26,6 @@ class Scripts_SelectDbScriptTest extends PHPUnit_Framework_TestCase { public function setUp() { parent::setUp(); - Class_Migration_UpdateConfig::setEcho(true); - Class_Migration_UpdateDatabaseAfterSelectDb::setEcho(true); $this->_db_name_to_restore = Bokeh_Engine::getInstance()->getDbName(); exec('cd ' . __DIR__ . '/../.. && php -f scripts/select_db.php bokeh_test_db'); } @@ -53,6 +51,6 @@ class Scripts_SelectDbScriptTest extends PHPUnit_Framework_TestCase { protected function _restorePreviousDBName() { - (new Class_Migration_UpdateConfig)->run($this->_db_name_to_restore); + (new Class_Migration_UpdateConfig)->runWithoutEcho($this->_db_name_to_restore); } }