From bd7e250d86465c0dcafd948c08655a2174d6e85e Mon Sep 17 00:00:00 2001 From: Patrick Barroca <pbarroca@afi-sa.fr> Date: Fri, 24 Jun 2022 11:45:29 +0200 Subject: [PATCH] hotline #159109 : fix CVS/GAM audio tracks detection - display tracks by sources - remove specific LastFm code from Intonation - Intonation audio tracks moved at bokeh core - historic tracks rendering use new audio tracks object --- VERSIONS_HOTLINE/159109 | 1 + .../opac/controllers/NoticeajaxController.php | 48 +- library/Class/AdminVar.php | 1 - library/Class/Notice.php | 5 - .../Track.php => Class/Notice/AudioTrack.php} | 8 +- library/Class/Notice/AudioTracks.php | 304 ++++++++++++ library/Class/Notice/AudioTracksVisitor.php | 29 ++ library/Class/Notice/TracksReader.php | 238 ---------- library/Class/NoticeUnimarc.php | 30 +- library/Class/NoticeUnimarc/Fluent.php | 123 ----- library/Class/NoticeUnimarc/Zone.php | 171 +++++++ library/ZendAfi/View/Helper/RenderTracks.php | 158 +++++++ .../Helper/Template/AlbumAudioJsPlayer.php | 4 +- .../templates/Intonation/Library/LastFm.php | 186 -------- .../templates/Intonation/Library/Picture.php | 27 +- .../Intonation/Library/Record/MediaHelper.php | 4 +- .../templates/Intonation/Library/Settings.php | 1 + .../templates/Intonation/Library/Tracks.php | 179 ------- .../Intonation/View/RenderTracks.php | 86 ++-- .../NoticeAjaxControllerMorceauxTest.php | 241 ++++++++++ tests/library/Class/NoticeTest.php | 73 +-- .../AlbumAudioRecord/AlbumAudioRecordTest.php | 49 +- tests/scenarios/Jamendo/JamendoTest.php | 33 +- .../Templates/ChiliRecordMediaTest.php | 176 ------- .../TemplatesDigitalResourcesTest.php | 10 - .../Templates/TemplatesJumbotronTest.php | 5 +- .../Templates/TemplatesMediaTest.php | 447 ++++++++++++++++++ tests/scenarios/Templates/TemplatesTest.php | 173 +------ 28 files changed, 1579 insertions(+), 1231 deletions(-) create mode 100644 VERSIONS_HOTLINE/159109 rename library/{templates/Intonation/Library/Track.php => Class/Notice/AudioTrack.php} (96%) create mode 100644 library/Class/Notice/AudioTracks.php create mode 100644 library/Class/Notice/AudioTracksVisitor.php delete mode 100644 library/Class/Notice/TracksReader.php create mode 100644 library/Class/NoticeUnimarc/Zone.php create mode 100644 library/ZendAfi/View/Helper/RenderTracks.php delete mode 100644 library/templates/Intonation/Library/LastFm.php delete mode 100644 library/templates/Intonation/Library/Tracks.php create mode 100644 tests/application/modules/opac/controllers/NoticeAjaxControllerMorceauxTest.php delete mode 100644 tests/scenarios/Templates/ChiliRecordMediaTest.php create mode 100644 tests/scenarios/Templates/TemplatesMediaTest.php diff --git a/VERSIONS_HOTLINE/159109 b/VERSIONS_HOTLINE/159109 new file mode 100644 index 00000000000..6d9cc8a9c34 --- /dev/null +++ b/VERSIONS_HOTLINE/159109 @@ -0,0 +1 @@ + - correctif #159109 : Magasin de thème : Amélioration de la détection des extraits sonores dans les notices CVS et Gam Annecy \ No newline at end of file diff --git a/application/modules/opac/controllers/NoticeajaxController.php b/application/modules/opac/controllers/NoticeajaxController.php index 0b787cacdf0..e24696b5b47 100644 --- a/application/modules/opac/controllers/NoticeajaxController.php +++ b/application/modules/opac/controllers/NoticeajaxController.php @@ -27,7 +27,7 @@ class NoticeAjaxController extends ZendAfi_Controller_Action { public function getPlugins() { - return ['ZendAfi_Controller_Plugin_Template_Jumbotron']; + return [ZendAfi_Controller_Plugin_Template_Jumbotron::class]; } @@ -48,9 +48,7 @@ class NoticeAjaxController extends ZendAfi_Controller_Action { protected function extractNoticeFromRequest() { $id_notice = str_replace('N','', $this->_request->getParam('id', $this->_getParam('id_notice'))); - if (!$notice = Class_Notice::find($id_notice)) - $notice = new Class_Notice(); - return $notice; + return Class_Notice::find($id_notice) ?? new Class_Notice; } @@ -286,27 +284,9 @@ class NoticeAjaxController extends ZendAfi_Controller_Action { public function morceauxAction() { session_write_close(); - if (!$this->notice->isTypeDocSonore()) - return false; - - // dans la notice - $morceaux=$this->notice->getMorceaux(); - $source=$morceaux['source']; - - // Chez LastFm - if (!$morceaux["nb_resultats"]) { - $source="Last.fm"; - $last_fm=new Class_WebService_Lastfm(); - $morceaux=$last_fm->getMorceaux($this->notice->getTitrePrincipal(), - $this->notice->getAuteurPrincipal()); - } - $morceaux["id_notice"] = $this->notice->getId(); - if (!$morceaux["nb_resultats"]) - $source = ''; - $morceaux["auteur"] = $this->notice->getAuteurPrincipal(); - $html = $this->notice_html->getMorceaux($morceaux,$source); - $this->_ajaxResponseWithScript($html); + $tracks = Class_Notice_AudioTracks::newFor($this->notice); + return $this->_ajaxResponseWithScript($this->view->renderTracks($tracks)); } @@ -589,9 +569,7 @@ class NoticeAjaxController extends ZendAfi_Controller_Action { public function tracksAction() { session_write_close(); - $tracks = (new Intonation_Library_Tracks) - ->setModel($this->notice) - ->collection(); + $tracks = Class_Notice_AudioTracks::newFor($this->notice)->collection(); $this->_ajaxResponseWithScript($this->view->renderTracks($tracks)); } @@ -600,9 +578,7 @@ class NoticeAjaxController extends ZendAfi_Controller_Action { public function mediaAction() { session_write_close(); - $tracks = (new Intonation_Library_Tracks) - ->setModel($this->notice) - ->collection(); + $tracks = Class_Notice_AudioTracks::newFor($this->notice)->collection(); $trailers = (new Intonation_Library_Trailers) ->setModel($this->notice) @@ -625,19 +601,13 @@ class NoticeAjaxController extends ZendAfi_Controller_Action { $html = array_filter($html); - $html = array_map(function($row) - { - return $this->view->div(['class' => 'col-12'], $row); - }, $html); + $html = array_map(fn($row) => $this->view->div(['class' => 'col-12'], $row), + $html); if (empty($html)) $html = $this->view->mediaPlaceholder(); - return $this->_helper->ajax(function() use ($html) - { - if ($html) - return $this->view->grid($html); - }); + return $this->_helper->ajax(fn() => $html ? $this->view->grid($html) : null); } diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php index 6454a13d299..ca71ae674cf 100644 --- a/library/Class/AdminVar.php +++ b/library/Class/AdminVar.php @@ -405,7 +405,6 @@ Pour vous désabonner de la lettre d\'information, merci de cliquer sur le lien 'MENU_BOITE' => Class_AdminVar_Meta::newOnOff($this->_('Activation des boîtes dans les menus')), 'INTERDIRE_MODIF_FICHE_ABONNE' => Class_AdminVar_Meta::newOnOff($this->_('Interdire la modification de la fiche abonne')), - 'ROOT_URL_ECOUTE' => Class_AdminVar_Meta::newDefault('URL de base à rajouter aux données unimarc pour la lecture des morceaux'), 'URL_TYPO3' => Class_AdminVar_Meta::newDefault($this->_('Url d\'import d\'un agenda TYPO3'))->bePrivate(), 'CHAMPS_FICHE_UTILISATEUR' => Class_AdminVar_Meta::newMultiInput($this->_('Liste des champs que l\'utilisateur peux modifier. <br/>Ex: nom;prenom;pseudo;adresse;<br/>code_postal;ville;mail;is_contact_mail;<br/>telephone;is_contact_telephone;')), 'FACETTE_PCDM4_LIBELLE' => Class_AdminVar_Meta::newDefault($this->_('Libellé pour la PCDM4')), diff --git a/library/Class/Notice.php b/library/Class/Notice.php index 425be833281..f4d4b0e9118 100644 --- a/library/Class/Notice.php +++ b/library/Class/Notice.php @@ -843,11 +843,6 @@ class Class_Notice extends Storm_Model_Abstract { } - public function getMorceaux() { - return Class_Notice_TracksReader::getTracksOf($this); - } - - public function getComplementTitre() : string { return $this->_getTitles()->getTitleSupplement(); } diff --git a/library/templates/Intonation/Library/Track.php b/library/Class/Notice/AudioTrack.php similarity index 96% rename from library/templates/Intonation/Library/Track.php rename to library/Class/Notice/AudioTrack.php index d6bee85217a..49d420e8320 100644 --- a/library/templates/Intonation/Library/Track.php +++ b/library/Class/Notice/AudioTrack.php @@ -20,8 +20,7 @@ */ -class Intonation_Library_Track { - +class Class_Notice_AudioTrack { protected string $_title = ''; protected string $_duration = ''; protected string $_source = ''; @@ -36,7 +35,7 @@ class Intonation_Library_Track { } - public function getTitle() : string{ + public function getTitle() : string { return $this->_title; } @@ -69,6 +68,7 @@ class Intonation_Library_Track { } + public function getAuthor() : string { return $this->_author; } @@ -104,4 +104,4 @@ class Intonation_Library_Track { public function isAudio() : bool { return ! $this->isYoutube(); } -} \ No newline at end of file +} diff --git a/library/Class/Notice/AudioTracks.php b/library/Class/Notice/AudioTracks.php new file mode 100644 index 00000000000..7b0e9b79579 --- /dev/null +++ b/library/Class/Notice/AudioTracks.php @@ -0,0 +1,304 @@ +<?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 Class_Notice_AudioTracks { + + protected Class_Notice $_record; + protected string $_title_zone = ''; + protected string $_title_field = ''; + protected string $_sample_zone = ''; + protected string $_sample_title_field = ''; + protected string $_sample_url_field = ''; + protected string $_source = ''; + + protected ?Storm_Collection $_tracks; + + + public static function newFor(Class_Notice $record) : self { + if (!$record->isTypeDocSonore()) + return new Class_Notice_AudioTracksEmpty($record); + + if ($record->isGam()) + return new Class_Notice_AudioTracksGam($record); + + if ($record->isCvs()) + return new Class_Notice_AudioTracksCvs($record); + + return new Class_Notice_AudioTracksBase($record); + } + + + public function __construct(Class_Notice $record) { + $this->_record = $record; + $this->_tracks = null; + } + + + public function acceptVisitor(Class_Notice_AudioTracksVisitor $visitor) : self { + $visitor + ->visitRecordId($this->_record->getId()) + ->visitRecordAuthor($this->_record->getAuteurPrincipal()) + ->visitSource($this->_source); + + $volumes = []; + $this->collection() + ->eachDo(function($track) use(&$volumes) + { + if (!isset($volumes[$track->getVolume()])) + $volumes[$track->getVolume()] = new Storm_Collection; + $volumes[$track->getVolume()]->add($track); + }); + + ksort($volumes, SORT_NUMERIC); + + foreach($volumes as $volume => $tracks) { + $tracks->eachDo(fn($track) => $visitor->visitTrack($track)); + $visitor->visitVolumeEnd($volume); + } + + return $this; + } + + + public function collection() : Storm_Collection { + return $this->_tracks ??= $this->_loadTracks(); + } + + + public function hasContent() : bool { + return $this->_title_zone && !empty($this->_record->get_subfield($this->_title_zone)); + } + + + public function hasSample() : bool { + return $this->_sample_zone && !empty($this->_record->get_subfield($this->_sample_zone)); + } + + + public function _loadTracks() : Storm_Collection { + $sample_zones = $this->_sampleZones(); + + $pairs = $this + ->_titleZones() + ->collect(fn($title_zone) => $this->_titleWithSamplePairFor($title_zone, $sample_zones)); + + return $pairs->collect(fn($pair) => $this->_newTrack($pair[0], $pair[1])); + } + + + protected function _titleZones() : Storm_Collection { + return $this->_zones($this->_title_zone) + ->select(fn($zone) => $zone->firstValueOf($this->_title_field)); + } + + + protected function _sampleZones() : ?Storm_Collection { + return $this->_title_zone !== $this->_sample_zone + ? $this->_zones($this->_sample_zone) + : null; + } + + + protected function _titleWithSamplePairFor(Class_NoticeUnimarc_Zone $title_zone, + ?Storm_Collection $sample_zones) : array { + $sample_zone = (null === $sample_zones) + ? $title_zone + : $sample_zones->detect(fn($sample_zone) => $this->_sampleZoneMatching($title_zone, + $sample_zone)); + + return [$title_zone, $sample_zone]; + } + + + protected function _sampleZoneMatching(Class_NoticeUnimarc_Zone $title_zone, + Class_NoticeUnimarc_Zone $sample_zone) : bool { + return $title_zone->isSameFieldValue($this->_title_field, $sample_zone); + } + + + protected function _newTrack(Class_NoticeUnimarc_Zone $title_zone, + ?Class_NoticeUnimarc_Zone $sample_zone) : Class_Notice_AudioTrack { + $track = (new Class_Notice_AudioTrack) + ->setTitle($title_zone->firstValueOf($this->_title_field)) + ->setSource($this->_source); + + return $this->_setUrlFrom($track, $sample_zone); + } + + + protected function _setUrlFrom(Class_Notice_AudioTrack $track, + ?Class_NoticeUnimarc_Zone $sample_zone) : Class_Notice_AudioTrack { + return $track->setUrl($sample_zone + ? $sample_zone->firstValueOf($this->_sample_url_field) + : ''); + } + + + protected function _zones(string $name) : Storm_Collection { + return (new Storm_Collection($this->_record->get_subfield($name))) + ->collect(fn($subfield) => $this->_record->get_zone($name, $subfield)); + } + + + protected function _detectTitleField(Class_Notice $record) : string { + return $record->get_subfield($this->_title_zone, 't') ? 't' : 'a'; + } + + + protected function _detectField(Class_Notice $record, string $zone, array $possibles) : ?string { + foreach($possibles as $possible) + if ($record->get_subfield($zone, $possible)) + return $possible; + + return null; + } + + + protected function _detectZone(Class_Notice $record, array $possibles) : ?string { + foreach($possibles as $zone) + if ($record->hasZone($zone)) + return $zone; + + return null; + } +} + + + + +class Class_Notice_AudioTracksEmpty extends Class_Notice_AudioTracks { + public function hasContent() : bool { + return false; + } + + + public function hasSample() : bool { + return false; + } + + + public function collection() : Storm_Collection { + return new Storm_Collection; + } +} + + + + +abstract class Class_Notice_AudioTracksThirdParty extends Class_Notice_AudioTracks { + protected function _sampleZoneMatching(Class_NoticeUnimarc_Zone $title_zone, + Class_NoticeUnimarc_Zone $sample_zone) : bool { + return ($title = trim($title_zone->firstValueOf($this->_title_field))) + && (null !== $sample_zone->detectFieldByValue($title)); + } + + + protected function _setUrlFrom(Class_Notice_AudioTrack $track, + ?Class_NoticeUnimarc_Zone $sample_zone) : Class_Notice_AudioTrack { + return $track->setUrl($sample_zone && ($field = $sample_zone->firstField()) + ? $field->getValue() + : ''); + } +} + + + + +class Class_Notice_AudioTracksGam extends Class_Notice_AudioTracksThirdParty { + protected string $_title_zone = '858'; + protected string $_title_field = 'z'; + protected string $_sample_zone = '858'; + protected string $_source = 'GAM Annecy'; + + public function __construct(Class_Notice $record) { + parent::__construct($record); + + $this->_sample_zone = $this->_detectZone($record, ['958', '964', '985', '858']) ?? $this->_sample_zone; + $this->_title_zone = $this->_detectZone($record, ['858', '464']) ?? $this->_title_zone; + + if ('464' === $this->_title_zone) + $this->_title_field = $this->_detectTitleField($record); + } +} + + + + +class Class_Notice_AudioTracksCvs extends Class_Notice_AudioTracksThirdParty { + protected string $_title_zone = '464'; + protected string $_title_field = 't'; + protected string $_sample_zone = '856'; + protected string $_source = 'CVS'; +} + + + + +class Class_Notice_AudioTracksBase extends Class_Notice_AudioTracks { + use Trait_Translator; + + protected string $_title_zone = '464'; + protected string $_title_field = 't'; + protected string $_sample_zone = '464'; + protected string $_sample_title_field = 't'; + protected string $_sample_url_field = '3'; + + public function __construct(Class_Notice $record) { + parent::__construct($record); + + $this->_source = $this->_('Bibliothèque'); + $this->_title_field = $this->_detectTitleField($record); + } + + + protected function _sampleZones() : ?Storm_Collection { + return ($samples = parent::_sampleZones()) + ? $samples->select(fn($zone) => ($zone->firstValueOf($this->_sample_title_field) + && $zone->firstValueOf($this->_sample_url_field))) + : null; +} + + + protected function _titleSampleZonesPairFor(Class_NoticeUnimarc_Zone $title_zone, + ?Storm_Collection $sample_zones) : array { + return ('a' === $this->_title_field) + ? [$title_zone, null] // ensure no sample data + : parent::_titleSampleZonesPairFor($title_zone, $sample_zones); + } + + + protected function _newTrack(Class_NoticeUnimarc_Zone $title_zone, + ?Class_NoticeUnimarc_Zone $sample_zone) : Class_Notice_AudioTrack { + return parent::_newTrack($title_zone, $sample_zone) + ->setVolume($title_zone->firstValueOf('v')) + ->setDuration($title_zone->firstValueOf('d')) + ->setAuthor($this->_authorFrom($title_zone)); + } + + + protected function _authorFrom(Class_NoticeUnimarc_Zone $zone) : string { + return implode(' ', + array_filter(('a' === $this->_title_field) + ? [$zone->firstValueOf('g'), $zone->firstValueOf('f')] + : [$zone->firstValueOf('b'), $zone->firstValueOf('a')])); + } +} diff --git a/library/Class/Notice/AudioTracksVisitor.php b/library/Class/Notice/AudioTracksVisitor.php new file mode 100644 index 00000000000..0d153efafe7 --- /dev/null +++ b/library/Class/Notice/AudioTracksVisitor.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 + */ + + +interface Class_Notice_AudioTracksVisitor { + public function visitRecordId(int $id) : self; + public function visitRecordAuthor(string $author) : self; + public function visitSource(string $source) : self; + public function visitVolumeEnd(string $volume) : self; + public function visitTrack(Class_Notice_AudioTrack $track) : self; +} diff --git a/library/Class/Notice/TracksReader.php b/library/Class/Notice/TracksReader.php deleted file mode 100644 index f89fd9bbad1..00000000000 --- a/library/Class/Notice/TracksReader.php +++ /dev/null @@ -1,238 +0,0 @@ -<?php -/** - * Copyright (c) 2012-2014, 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_Notice_TracksReader { - const SOURCE = 'source'; - const NB_RESULTATS = 'nb_resultats'; - const NOMBRE_VOLUMES = 'nombre_volumes'; - const MORCEAUX = 'morceaux'; - const TITRE = 'titre'; - const URL_ECOUTE = 'url_ecoute'; - - - public static function getTracksOf($record) { - if (0 == count($record->get_subfield('464', '3'))) { - $clazz = null; - if ($record->isGam()) - $clazz = 'Class_Notice_TracksReader_Gam'; - if ($record->isCvs()) - $clazz = 'Class_Notice_TracksReader_Cvs'; - - if ($clazz) - return (new $clazz($record))->getTracks(); - } - - return (new Class_Notice_TracksReader_Local($record))->getTracks(); - } - - - public function __construct($record) { - $this->_record = $record; - } - - - public function getTracks() { - return [static::NB_RESULTATS => 0, - static::NOMBRE_VOLUMES => 0, - static::MORCEAUX => [], - static::SOURCE => $this->getSource()]; - } - - - public function getSource() { - return 'Bibliothèque'; - } -} - - - -class Class_Notice_TracksReader_Local extends Class_Notice_TracksReader { - public function getMapping($datas) { - foreach($datas as $data) { - $subfields = $this->_record->decoupe_bloc_champ($data); - foreach ($subfields as $subfield) { - if ($subfield['code'] == 't') { - return ['t' => 'titre', - 'd' => 'duree', - 'a' => 'auteur_nom', - 'b' => 'auteur_prenom', - 'v' => 'volume', - '3' => 'url_ecoute']; - } - } - } - - return ['a' => 'titre', - 'd' => 'duree', - 'f' => 'auteur_nom', - 'g' => 'auteur_prenom', - 'v' => 'volume']; - } - - public function getTracks() { - $ret = parent::getTracks(); - - // get zone 464 - $datas = array_filter( - $this->_record->get_subfield('464'), - function($champ) { - return false !== $this->_record->decoupe_bloc_champ($champ)[0]['code']; - }); - - if(!count($datas)) - return $ret; - - $root_url_ecoute = Class_AdminVar::get('ROOT_URL_ECOUTE'); - $mapping = $this->getMapping($datas); - - $volume = $piste = 0; - foreach($datas as $champs) { - $champ = $this->_record->decoupe_bloc_champ($champs); - $titre = $auteur_nom = $auteur_prenom = $duree = $volume = $url_ecoute = ''; - foreach($champ as $sous_champ) - if (array_key_exists($sous_champ['code'], $mapping)) - ${$mapping[$sous_champ['code']]} = $sous_champ['valeur']; - - if (!$titre) - continue; - - if ($auteur_prenom) - $auteur_nom = $auteur_prenom . ' ' . $auteur_nom; - - if ($auteur_nom) - $titre .= ' / ' . $auteur_nom; - - if ($duree) - $titre .= ' ' . $duree; - - $piste++; - - if (!$volume) - $volume = 1; - - $ret['nb_resultats'] = $piste; - if ($volume > $ret['nombre_volumes']) - $ret['nombre_volumes'] = $volume; - - $ret['morceaux'][$volume][$piste]['titre'] = $titre; - if ($url_ecoute) - $ret['morceaux'][$volume][$piste]['url_ecoute'] = $root_url_ecoute . $url_ecoute; - } - - return $ret; - } -} - - - -class Class_Notice_TracksReader_ThirdParty extends Class_Notice_TracksReader { - protected $_titles_sources, $_samples_sources = []; - - - public function getTitles() { - return $this->_getFirstFoundFieldIn($this->_titles_sources); - } - - - public function getSamples() { - $datas = $this->_getFirstFoundFieldIn($this->_samples_sources); - - if (0 == count($datas)) - return []; - - $ret = []; - $indice = 0; - - foreach ($datas as $bloc) { - $ret[$indice] = $this->_record->getValeursBloc($bloc); - $trav = explode('/', $ret[$indice][1]); - $ret[$indice][1] = trim($trav[0]); - $indice++; - } - return $ret; - } - - - protected function _getFirstFoundFieldIn($possibles) { - $datas = []; - foreach ($possibles as $possible) { - $datas = call_user_func_array([$this->_record, 'get_subfield'], $possible); - if (0 < count($datas)) - return $datas; - } - return $datas; - } - - - public function getTracks() { - $ret = parent::getTracks(); - - $titles = $this->getTitles(); - if(!count($titles)) - return $ret; - - $samples = $this->getSamples(); - - $volume = 1; - $piste = 0; - foreach($titles as $title) { - $piste++; - $ret[static::NB_RESULTATS] = $piste; - $ret[static::MORCEAUX][$volume][$piste][static::TITRE] = $title; - - if (!$samples) - continue; - - foreach($samples as $sample) { - if (trim($title) == trim($sample[1])) { - $ret[static::MORCEAUX][$volume][$piste][static::URL_ECOUTE] = $sample[0]; - break; - } - } - } - - return $ret; - } -} - - - -class Class_Notice_TracksReader_Gam extends Class_Notice_TracksReader_ThirdParty { - protected $_titles_sources = [['858', 'z'], ['464', 't'], ['464', 'a']]; - protected $_samples_sources = [['958'], ['964'], ['985'], ['858']]; - - public function getSource() { - return 'GAM Annecy'; - } -} - - - -class Class_Notice_TracksReader_Cvs extends Class_Notice_TracksReader_ThirdParty { - protected $_titles_sources = [['464', 't']]; - protected $_samples_sources = [['856']]; - - public function getSource() { - return 'CVS'; - } -} -?> \ No newline at end of file diff --git a/library/Class/NoticeUnimarc.php b/library/Class/NoticeUnimarc.php index 624220d5aac..a87a4ccce41 100644 --- a/library/Class/NoticeUnimarc.php +++ b/library/Class/NoticeUnimarc.php @@ -140,6 +140,18 @@ class Class_NoticeUnimarc { } + public function getZoneCount(string $zone) : int { + return isset($this->inner_data[$zone]) + ? count($this->inner_data[$zone]) + : 0; + } + + + public function hasZone(string $zone) : bool { + return 0 < $this->getZoneCount($zone); + } + + public function get_subfield_with_indicators($zone, $subfield, $indicators){ $values = new Storm_Collection(); @@ -325,16 +337,18 @@ class Class_NoticeUnimarc { } - public function get_field($zone) { - $instance = new Class_Entity(); + public function get_zone(string $label, string $content) : Class_NoticeUnimarc_Zone { + $content = str_replace($this->rgx_field_end, '', $content); + $instance = (new Class_NoticeUnimarc_Zone)->label($label); - $bloc = substr($zone, 3); - $fields = explode($this->subfield_begin, $bloc); + if ('00' === substr($label, 0, 2)) + return $instance->content($content); - foreach($fields as $field) { - $set = 'set' . substr($field, 0, 1); - $instance->$set(substr($field, 1)); - } + $instance->indicators(substr($content, 0, 2)); + $bloc = substr($content, 3); + + foreach(explode($this->subfield_begin, $bloc) as $field) + $instance->addChild(substr($field, 0, 1), substr($field, 1)); return $instance; } diff --git a/library/Class/NoticeUnimarc/Fluent.php b/library/Class/NoticeUnimarc/Fluent.php index 6914b8b95df..a720f8b3e88 100644 --- a/library/Class/NoticeUnimarc/Fluent.php +++ b/library/Class/NoticeUnimarc/Fluent.php @@ -187,129 +187,6 @@ class Class_NoticeUnimarc_AuthorityLabel { -class Class_NoticeUnimarc_Zone { - protected - $_label, - $_indicators = ' ', - $_sub_zones, - $_content; - - public function __construct() { - $this->_sub_zones = new Storm_Collection(); - } - - - public function label($label) { - $this->_label = $label; - return $this; - } - - - public function isLabel($label) { - return $label == $this->_label; - } - - - public function content($content) { - $this->_content = $content; - $this->_sub_zones = new Storm_Collection(); - return $this; - } - - - public function children($children) { - foreach($children as $code => $value) - $this->addChild($code, $value); - - return $this; - } - - - public function addChild($code, $value) { - $this->_sub_zones - ->append(new Class_NoticeUnimarc_SubZone($code, $value)); - - $this->_content = null; - return $this; - } - - - public function indicators($indicators) { - $this->_indicators = $indicators; - return $this; - } - - - public function detectFieldByCode($code) { - return $this->detectField(function($field) use($code) - { - return $field->isCode($code); - }); - } - - - public function detectField($callback) { - return $this->_sub_zones->detect($callback); - } - - - public function render() { - $content = $this->_content - ? $this->_content - : ($this->_indicators . implode($this->_sub_zones - ->collect(function($zone) { return $zone->render(); }) - ->getArrayCopy())); - - return $content . chr(0x1e); - } - - - public function directoryWith($length, $address) { - return sprintf('%03d%04d%05d', $this->_label, $length, $address); - } -} - - - -class Class_NoticeUnimarc_SubZone { - protected - $_code, - $_value; - - public function __construct($code, $value) { - $this->_code = $code; - $this->_value = $value; - } - - public function code($code) { - $this->_code = $code; - return $this; - } - - - public function isCode($code) { - return $code == $this->_code; - } - - - public function value($value) { - $this->_value = $value; - return $this; - } - - - public function getValue() { - return $this->_value; - } - - - public function render() { - return chr(0x1f) . $this->_code . $this->_value; - } -} - - - class Class_NoticeUnimarc_LegacyVisitor { protected $_fluent; diff --git a/library/Class/NoticeUnimarc/Zone.php b/library/Class/NoticeUnimarc/Zone.php new file mode 100644 index 00000000000..6c95c613c77 --- /dev/null +++ b/library/Class/NoticeUnimarc/Zone.php @@ -0,0 +1,171 @@ +<?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_NoticeUnimarc_Zone { + protected + $_label, + $_indicators = ' ', + $_sub_zones, + $_content; + + public function __construct() { + $this->_sub_zones = new Storm_Collection; + } + + + public function label(string $label) : self { + $this->_label = $label; + return $this; + } + + + public function isLabel(string $label) : bool { + return $label == $this->_label; + } + + + public function content(string $content) : self { + $this->_content = $content; + $this->_sub_zones = new Storm_Collection; + return $this; + } + + + public function children(array $children) : self { + foreach($children as $code => $value) + $this->addChild($code, $value); + + return $this; + } + + + public function addChild(string $code, string $value) : self { + $this->_sub_zones + ->append(new Class_NoticeUnimarc_SubZone($code, $value)); + + $this->_content = null; + return $this; + } + + + public function indicators(string $indicators) : self { + $this->_indicators = $indicators; + return $this; + } + + + public function detectFieldByCode(string $code) : ?Class_NoticeUnimarc_SubZone { + return $this->detectField(fn($field) => $field->isCode($code)); + } + + + public function detectFieldByValue(string $value) : ?Class_NoticeUnimarc_SubZone { + return $this->detectField(fn($field) => $field->isValue($value)); + } + + + public function detectField(Closure $callback) : ?Class_NoticeUnimarc_SubZone { + return $this->_sub_zones->detect($callback); + } + + + public function firstValueOf(string $code) : string { + return ($field = $this->detectFieldByCode($code)) + ? $field->getValue() + : ''; + } + + + public function firstField() : ?Class_NoticeUnimarc_SubZone { + return $this->_sub_zones->first(); + } + + + public function render() : string { + $content = $this->_content + ? $this->_content + : ($this->_indicators . implode($this->_sub_zones + ->collect(fn($zone) => $zone->render()) + ->getArrayCopy())); + + return $content . chr(0x1e); + } + + + public function directoryWith(int $length, int $address) { + return sprintf('%03d%04d%05d', $this->_label, $length, $address); + } + + + public function isSameFieldValue(string $my_field, + Class_NoticeUnimarc_Zone $other_zone, + string $other_field) : bool { + return trim($this->firstValueOf($my_field)) + === trim($other_zone->firstValueOf($other_field)); + } +} + + + + +class Class_NoticeUnimarc_SubZone { + protected + $_code, + $_value; + + public function __construct(string $code, string $value) { + $this->_code = $code; + $this->_value = $value; + } + + + public function code(string $code) : self { + $this->_code = $code; + return $this; + } + + + public function isCode(string $code) : bool { + return $code == $this->_code; + } + + + public function value(string $value) : self { + $this->_value = $value; + return $this; + } + + + public function getValue() : string { + return $this->_value ?? ''; + } + + + public function isValue(string $value) : bool { + return trim($value) === trim($this->getValue()); + } + + + public function render() : string { + return chr(0x1f) . $this->_code . $this->_value; + } +} diff --git a/library/ZendAfi/View/Helper/RenderTracks.php b/library/ZendAfi/View/Helper/RenderTracks.php new file mode 100644 index 00000000000..f6b3cfc87b6 --- /dev/null +++ b/library/ZendAfi/View/Helper/RenderTracks.php @@ -0,0 +1,158 @@ +<?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_RenderTracks + extends ZendAfi_View_Helper_BaseHelper + implements Class_Notice_AudioTracksVisitor { + + protected string $_source; + protected array $_volumes; + protected array $_tracks; + protected string $_video_img; + protected int $_record_id; + protected string $_record_author; + + + public function renderTracks(Class_Notice_AudioTracks $tracks) : string { + $this->_volumes = []; + $this->_tracks = []; + $this->_video_img = Class_Profil::getCurrentProfil()->getUrlImage('bouton/voir_video.png'); + $this->_record_id = 0; + $this->_record_author = ''; + + $tracks->acceptVisitor($this); + + return $this->_render(); + } + + + public function visitRecordId(int $id) : self { + $this->_record_id = $id; + return $this; + } + + + public function visitRecordAuthor(string $author) : self { + $this->_record_author = $author; + return $this; + } + + + public function visitSource(string $source) : self { + $this->_source = $source; + return $this; + } + + + public function visitVolumeEnd(string $volume) : self { + if ($this->_tracks) + $this->_volumes[$volume] = $this->_tracks; + + $this->_tracks = []; + return $this; + } + + + public function visitTrack(Class_Notice_AudioTrack $track) : self { + $this->_tracks[] = $track; + return $this; + } + + + protected function _render() : string { + if (!$this->_volumes) + return '<table width="100%"><tr><td>' + . $this->_('Aucune information n\'a été trouvée') + . '</td></tr></table>'; + + $html = []; + foreach($this->_volumes as $k => $tracks) + $html[] = $this->_renderVolume($k, $tracks); + + return ($this->_source + ? $this->_div(['class' => 'notice_info_titre'], + $this->_tag('h3', + $this->_('Source : %s', $this->_source))) + : '') + . + implode($html); + } + + + protected function _renderVolume(string $volume, array $tracks) : string { + return + (1 < count($this->_volumes) + ? $this->_div(['class' => 'notice_info_ligne_titre'], + $this->_('Volume n° %d', $volume)) + : '') + . + $this->_tag('ul', + implode(array_map(fn($pos, $track) => $this->_renderTrack($pos, $track, $volume), + array_keys($tracks), + $tracks))); + } + + + protected function _renderTrack(int $position, + Class_Notice_AudioTrack $track, + string $volume) : string { + $position++; + + $id_div = $this->_record_id . "_" . $volume . "_" . $position; + + $js_video = "chercher_videos('".$id_div."','".addslashes($this->_record_author)."','".addslashes($track->getTitle())."')"; + + $img_video = $this->view->tagImg($this->_video_img, + ['border' => '0', + 'onclick' => $js_video, + 'style' => 'cursor:pointer', + 'title' => $this->_('Clip vidéo')]); + + $img_close = $this->view->tagImg(URL_IMG.'bouton/contracter.gif', + ['border' => '0', + 'onclick' => "afficher_media('".$id_div."','close','')", + 'style' => 'cursor:pointer', + 'title' => $this->_('Replier')]); + + $img_ecoute = ($url = $track->getUrl()) + ? $this->view->audioJsPlayer($url) + : ' '; + + + $title = $track->getTitle(); + if ($author = $track->getAuthor()) + $title .= ' / ' . $author; + + if ($duration = $track->getDuration()) + $title .= ' ' . $duration; + + return $this + ->_tag('li', + $this->_div([], $img_video . $img_close) + . $this->_div(['class' => 'notice_info_ligne'], + $position . ': ' . $title) + . $img_ecoute + . $this->_div(['id' => $id_div, + 'rel' => 'video', + 'style' => 'display:none'])); + } +} diff --git a/library/ZendAfi/View/Helper/Template/AlbumAudioJsPlayer.php b/library/ZendAfi/View/Helper/Template/AlbumAudioJsPlayer.php index e25d40cfed3..56b363e9c8f 100644 --- a/library/ZendAfi/View/Helper/Template/AlbumAudioJsPlayer.php +++ b/library/ZendAfi/View/Helper/Template/AlbumAudioJsPlayer.php @@ -23,11 +23,11 @@ class ZendAfi_View_Helper_Template_AlbumAudioJsPlayer extends ZendAfi_View_Helper_BaseHelper { public function albumAudioJsPlayer($album) { - $tracks = (new Storm_Model_Collection($album->getAudioTracks())) + $tracks = (new Storm_Collection($album->getAudioTracks())) ->collect(function($track) { return - (new Intonation_Library_Track) + (new Class_Notice_AudioTrack) ->setTitle($track->findTitle()) ->setSource($track->getLicense()) ->setUrl($track->getPlayRessourceUrl()); diff --git a/library/templates/Intonation/Library/LastFm.php b/library/templates/Intonation/Library/LastFm.php deleted file mode 100644 index 238e1ea7c7c..00000000000 --- a/library/templates/Intonation/Library/LastFm.php +++ /dev/null @@ -1,186 +0,0 @@ -<?php -/** - * Copyright (c) 2012-2019, Agence Française Informatique (AFI). All rights reserved. - * - * BOKEH is free software; you can redistribute it and/or modify - * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by - * the Free Software Foundation. - * - * There are special exceptions to the terms and conditions of the AGPL as it - * is applied to this software (see README file). - * - * BOKEH is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU AFFERO GENERAL PUBLIC LICENSE for more details. - * - * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE - * along with BOKEH; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -class Intonation_Library_LastFm extends Class_Entity { - use Trait_Translator, Trait_SimpleWebClient; - - const - IMGS_XPATH = '//ul[@class="image-list"]/li/a/img', - TRACKS_XPATH = '//section[@id="tracks-section"]//table//td/a[contains(@class, "chartlist-play-button")]', - LAST_FM_IMGS = '/+images/', - LAST_FM = 'https://www.last.fm/music/'; - - - protected $_author_cache; - - - protected function _getAuthor() { - if ( $this->_author_cache) - return $this->_author_cache; - - return $this->_author_cache = $this->getModel()->getMainAuthorFromCodif(); - } - - - public function getAlbumPictures() { - return $this->_getPictures($this->_getAuthor()); - } - - - public function getAlbumTracks() { - return $this->_getTracks($this->_getAuthor(), $this->getModel()->getTitrePrincipal(' ')); - } - - - public function hasTracks() { - if ( ! $author = $this->_getAuthor()) - return false; - - if ( ! $album = $this->getModel()->getTitrePrincipal(' ')) - return false; - - return $this->_tryUrl(static::LAST_FM . urlencode($author) . '/' . urlencode($album)); - } - - - public function hasPictures() { - if (! $this->_getAuthor()) - return false; - - return $this->_tryUrl(static::LAST_FM . urlencode($this->_getAuthor()) . static::LAST_FM_IMGS); - } - - - protected function _tryUrl($url) { - if (!$response = static::getWebClient()->getResponse($url)) - return ''; - - return $response->isSuccessful() - ? $response->getBody() - : ''; - } - - - protected function _getTracks($author, $album) { - if (!$author) - return []; - - if (!$album) - return []; - - return - $this->_withUrlDo(static::LAST_FM . urlencode($author) . '/' . urlencode($album), - function($body) - { - return $this->_extractTracksFrom($body); - }); - } - - - protected function _withUrlDo($url, $callback) { - return ($body = $this->_tryUrl($url)) - ? $callback($body) - : []; - } - - - protected function _getPictures($author) { - if (!$author) - return []; - - return - $this->_withUrlDo(static::LAST_FM . urlencode($author) . static::LAST_FM_IMGS, - function($body) - { - return $this->_extractPicturesFrom($body); - }); - } - - - protected function _extractPicturesFrom($html) { - return $this->_withHtmlXpathDo($html, - static::IMGS_XPATH, - function($element, $elements) - { - if (!$url = str_replace('avatar170s', - '1024x0', - $element->getAttribute('src'))) - return $elements; - - $title = $this->_('Illustration du document %s de %s', - $this->getModel()->getTitrePrincipal(' '), - $this->getModel()->getMainAuthorFromCodif()); - - $elements [] = - new Intonation_Library_Picture(['Src' => $url, - 'Source' => 'Last.fm', - 'Title' => $title]); - - return $elements; - }); - } - - - protected function _extractTracksFrom($html) { - return $this->_withHtmlXpathDo($html, - static::TRACKS_XPATH, - function ($element, $elements) - { - if (!$url = str_replace('watch?v=', 'embed/', $element->getAttribute('href'))) - return $elements; - - if (!$title = $element->getAttribute('data-track-name')) - return $elements; - - $elements [] = (new Intonation_Library_Track) - ->setUrl($url) - ->setSource('Youtube - Last.fm') - ->setTitle($title); - - return $elements; - }); - } - - - protected function _withHtmlXpathDo($html, $xpath, $callback) { - $dom = new DOMDocument(); - - try { - $dom->loadHTML($html); - } catch (Exception $e) { - return []; - } - - if (!$dom_xpath = new DOMXpath($dom)) - return []; - - if (!$elements = $dom_xpath->query($xpath)) - return []; - - $collected = []; - - foreach($elements as $element) - $collected = $callback($element, $collected); - - return $collected; - } -} diff --git a/library/templates/Intonation/Library/Picture.php b/library/templates/Intonation/Library/Picture.php index 16c734a838e..82a0baf283b 100644 --- a/library/templates/Intonation/Library/Picture.php +++ b/library/templates/Intonation/Library/Picture.php @@ -20,4 +20,29 @@ */ -class Intonation_Library_Picture extends Class_Entity {} \ No newline at end of file +class Intonation_Library_Picture { + protected string $_url; + protected string $_source; + protected string $_title; + + public function __construct(string $url, string $source, string $title) { + $this->_url = $url; + $this->_source = $source; + $this->_title = $title; + } + + + public function getUrl() : string { + return $this->_url; + } + + + public function getSource() : string { + return $this->_source; + } + + + public function getTitle() : string { + return $this->_title; + } +} \ No newline at end of file diff --git a/library/templates/Intonation/Library/Record/MediaHelper.php b/library/templates/Intonation/Library/Record/MediaHelper.php index 98519b44d95..298ebef48ef 100644 --- a/library/templates/Intonation/Library/Record/MediaHelper.php +++ b/library/templates/Intonation/Library/Record/MediaHelper.php @@ -49,9 +49,7 @@ class Intonation_Library_Record_MediaHelper { ->hasContent()) return true; - if ((new Intonation_Library_Tracks) - ->setModel($this->_record) - ->hasContent()) + if (Class_Notice_AudioTracks::newFor($this->_record)->hasSample()) return true; return false; diff --git a/library/templates/Intonation/Library/Settings.php b/library/templates/Intonation/Library/Settings.php index 1481b84268b..b14ae934e1b 100644 --- a/library/templates/Intonation/Library/Settings.php +++ b/library/templates/Intonation/Library/Settings.php @@ -347,6 +347,7 @@ class Intonation_Library_Settings extends Intonation_System_Abstract { 'a class browse_shelf' => 'badge-secondary', 'div class items_shelf' => 'col-12', 'div class title_sibling_picto' => 'd-inline-block', + 'h3 class tracks_source' => 'd-none', ], 'icons_map_doc_types' => [], diff --git a/library/templates/Intonation/Library/Tracks.php b/library/templates/Intonation/Library/Tracks.php deleted file mode 100644 index 072690da7a9..00000000000 --- a/library/templates/Intonation/Library/Tracks.php +++ /dev/null @@ -1,179 +0,0 @@ -<?php -/** - * Copyright (c) 2012-2019, Agence Française Informatique (AFI). All rights reserved. - * - * BOKEH is free software; you can redistribute it and/or modify - * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by - * the Free Software Foundation. - * - * There are special exceptions to the terms and conditions of the AGPL as it - * is applied to this software (see README file). - * - * BOKEH is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU AFFERO GENERAL PUBLIC LICENSE for more details. - * - * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE - * along with BOKEH; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -class Intonation_Library_Tracks { - - protected $_model; - - - public function setModel($model) { - $this->_model = $model; - return $this; - } - - - public function collection() { - return new Storm_Model_Collection($this->tracks()); - } - - - public function hasContent() { - if (!$this->_model->isTypeDocSonore()) - return false; - - if ($this->_hasTracks()) - return true; - - return (new Intonation_Library_LastFm) - ->setModel($this->_model) - ->hasTracks(); - } - - - protected function _hasTracks() { - return $this->_model->isGam() - ? ((new Intonation_Library_TracksGam) - ->setModel($this->_model) - ->hasContent()) - : ((new Intonation_Library_TracksBase) - ->setModel($this->_model) - ->hasContent()); - } - - - public function tracks() { - if (!$this->_model->isTypeDocSonore()) - return []; - - $tracks = ($this->_model->isGam()) - ? ((new Intonation_Library_TracksGam) - ->setModel($this->_model) - ->getTracks()) - : ((new Intonation_Library_TracksBase) - ->setModel($this->_model) - ->getTracks()); - - if (!$more_tracks = (new Intonation_Library_LastFm) - ->setModel($this->_model) - ->getAlbumTracks()) - return $tracks; - - return array_merge($tracks, $more_tracks); - } -} - - - -abstract class Intonation_Library_TracksAbstract { - - protected $_model; - - - public function setModel($model) { - $this->_model = $model; - return $this; - } - - - abstract public function getTracks(); - abstract protected function _trackFromUnimarc($unimarc, $tracks); -} - - - -class Intonation_Library_TracksBase extends Intonation_Library_TracksAbstract { - - - public function hasContent() { - return ! empty($this->_model->get_subfield('464')); - } - - - public function getTracks() { - $tracks = []; - $unimarc = $this->_model->get_subfield('464'); - - foreach ($unimarc as $unimarc_track) - $tracks = $this->_trackFromUnimarc($unimarc_track, $tracks); - - return $tracks; - } - - - protected function _trackFromUnimarc($unimarc, $tracks) { - $field = $this->_model->get_field($unimarc); - - if (!$title = $field->gett()) - return $tracks; - - if (!$url = $field->get3()) - return $tracks; - - $tracks [] = (new Intonation_Library_Track) - ->setTitle($title) - ->setDuration((string) $field->getd()) - ->setSource('CVS') - ->setAuthor(implode(' ', [$field->geta(), - $field->getb()])) - ->setVolume((string) $field->getv()) - ->setUrl($url); - - return $tracks; - } -} - - - -class Intonation_Library_TracksGam extends Intonation_Library_TracksAbstract { - public function hasContent() { - return ! empty($this->_model->get_subfield('856')); - } - - - public function getTracks() { - $tracks = []; - $unimarc = $this->_model->get_subfield('856'); - - foreach ($unimarc as $unimarc_track) - $tracks = $this->_trackFromUnimarc($unimarc_track, $tracks); - - return $tracks; - } - - - protected function _trackFromUnimarc($unimarc, $tracks) { - $field = $this->_model->get_field($unimarc); - - if (!$title = $field->getz()) - return $tracks; - - if (!$url = $field->getu()) - return $tracks; - - $tracks [] = (new Intonation_Library_Track) - ->setTitle($title) - ->setSource('GAM') - ->setUrl($url); - - return $tracks; - } -} \ No newline at end of file diff --git a/library/templates/Intonation/View/RenderTracks.php b/library/templates/Intonation/View/RenderTracks.php index 7f9bb134a5c..f3f5a4c161c 100644 --- a/library/templates/Intonation/View/RenderTracks.php +++ b/library/templates/Intonation/View/RenderTracks.php @@ -21,59 +21,77 @@ class Intonation_View_RenderTracks extends ZendAfi_View_Helper_BaseHelper { - public function renderTracks($tracks) { + protected ?string $_track_icon; + protected ?string $_youtube_icon; + + + public function renderTracks(Storm_Collection $tracks) : string { + $tracks = $tracks->select(fn($track) => $track->getUrl()); if ($tracks->isEmpty()) return ''; - $html = [$this->_renderAudioTracks($tracks->select('isAudio')), - $this->_renderYoutubeTracks($tracks->select('isYoutube'))]; - - $html = array_filter($html); + $html = [$this->_renderAudioTracks($tracks->select(fn($track) => $track->isAudio())), + $this->_renderYoutubeTracks($tracks->select(fn($track) => $track->isYoutube()))]; - $html = array_map(function($content) - { - return $this->_div(['class' => 'col-12'], - $content); - }, - $html); + $html = array_map(fn($content) => $this->_div(['class' => 'col-12'], $content), + array_filter($html)); return $this->view->grid($html); } - protected function _renderAudioTracks($tracks) { + protected function _renderAudioTracks(Storm_Collection $tracks) : string { if ($tracks->isEmpty()) return ''; - $html = [$this->_div(['class' => 'col-12'], - $this->view->renderList($tracks, function($track) - {return $this->_audioTrack($track);})), + $by_sources = []; + $tracks + ->eachDo(function($track) use(&$by_sources) + { + if (!isset($by_sources[$track->getSource()])) + $by_sources[$track->getSource()] = new Storm_Collection; + $by_sources[$track->getSource()]->add($track); + }); - $this->_div(['class' => 'col-12'], - $this->_renderPlayer())]; + $html = array_map(fn($source, $tracks) => $this->_renderAudioTracksBySource($tracks, $source), + array_keys($by_sources), $by_sources); + + $html[] = $this->_div(['class' => 'col-12'], $this->_renderPlayer()); return $this->view->grid($html, ['class' => 'audio_tracks']); } - protected function _renderYoutubeTracks($tracks) { + protected function _renderAudioTracksBySource(Storm_Collection $tracks, + string $source) : string { + return + ($source + ? $this->_tag('h3', $this->_('Source : %s', $source), + ['class' => 'tracks_source']) + : '') + . + $this->_div(['class' => 'col-12'], + $this->view->renderList($tracks, + fn($track) => $this->_audioTrack($track))); + } + + + + protected function _renderYoutubeTracks(Storm_Collection $tracks) : string { if ($tracks->isEmpty()) return ''; $html = $this->_div(['class' => 'col-12'], - $this->view->renderList($tracks, function($track) - {return $this->_youtubeTrack($track);})); + $this->view->renderList($tracks, + fn($track) => $this->_youtubeTrack($track))); return $this->view->grid($html, ['class' => 'youtube_tracks']); } - protected function _audioTrack($track) { - $html = [$this->view->templateIco('track', 'utils'), - - $this->_tag('span', $track->getTitle(),['class' => 'track_title']), - - $this->_tag('span', $track->getSource(),['class' => 'track_source'])]; + protected function _audioTrack(Class_Notice_AudioTrack $track) : string { + $html = [$this->_trackIcon(), + $this->_tag('span', $track->getTitle(), ['class' => 'track_title'])]; return $this->_tag('a', implode($html), @@ -94,8 +112,8 @@ class Intonation_View_RenderTracks extends ZendAfi_View_Helper_BaseHelper { } - protected function _youtubeTrack($track) { - $html = [$this->view->templateIco('youtube', 'utils'), + protected function _youtubeTrack(Class_Notice_AudioTrack $track) { + $html = [$this->_youtubeIcon(), $this->_tag('span', $track->getTitle(), @@ -112,4 +130,14 @@ class Intonation_View_RenderTracks extends ZendAfi_View_Helper_BaseHelper { return $this->view->grid($html); } -} \ No newline at end of file + + + protected function _trackIcon() : string { + return $this->_track_icon ??= $this->view->templateIco('track', 'utils'); + } + + + protected function _youtubeIcon() : string { + return $this->_youtube_icon ??= $this->view->templateIco('youtube', 'utils'); + } +} diff --git a/tests/application/modules/opac/controllers/NoticeAjaxControllerMorceauxTest.php b/tests/application/modules/opac/controllers/NoticeAjaxControllerMorceauxTest.php new file mode 100644 index 00000000000..5f69fef3eab --- /dev/null +++ b/tests/application/modules/opac/controllers/NoticeAjaxControllerMorceauxTest.php @@ -0,0 +1,241 @@ +<?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 NoticeAjaxControllerMorceauxGamTest extends AbstractControllerTestCase { + protected array $_titles = ['Nuit', + 'A quoi tu sers ?', + 'Il suffira d\'un signe', + 'Un, deux, trois', + 'Je commence demain', + 'Peurs', + 'Medley : Quand la musique est bonne/Au bout de mes rêves/Comme toi/Long is the road (Américain)/La vie par procuration/Pas toi', + 'Je l\'aime aussi', + 'Là -bas', + 'Vivre cent vies', + 'C\'est pas d\'l\'amour', + 'A nos actes manqués', + 'Je marche seul']; + + protected array $_titles_with_sample = ['Nuit', + 'A quoi tu sers ?', + 'Il suffira d\'un signe', + 'Un, deux, trois', + 'Je commence demain']; + + + public function setUp() { + parent::setUp(); + + $this->fixture(Class_TypeDoc::class, + ['id' => 8, + 'label' => 'mp3', + 'famille_id' => Class_CodifTypeDoc::SONORE]); + + $unimarc = (new Class_NoticeUnimarc_Fluent) + ->zoneWithContent('001', '104363') + ->zoneWithChildren('200', ['a' => 'Sur scène', + 'f' => 'Fredericks, Goldman, Jones']) + ->zoneWithChildren('710', ['a' => 'Fredericks, Goldman, Jones', + '4' => 590, + '6' => 'Interprète']) + ->zoneWithChildren('801', ['a' => 'FR', 'b' => 'GAM']) + ->zoneWithChildren('856', ['u' => 'https://www.gamannecy.com/upload/albums/202007/0888750979728_thumb.jpg', + 'z' => 'Fredericks, Goldman, Jones / Sur scène']) + + ; + + $this->_addTitlesTo($unimarc); + + foreach($this->_titles_with_sample as $k => $title) + $unimarc->zoneWithChildren('958', ['u' => 'https://www.gamannecy.com/' . $k . '.mp3', + 'z' => $title]); + + $this->fixture(Class_Notice::class, + ['id' => 18238, + 'type_doc' => 8, + 'unimarc' => $unimarc->render()]); + + $this->dispatch('/opac/noticeajax/morceaux/id/18238'); + } + + + protected function _addTitlesTo(Class_NoticeUnimarc_Fluent $unimarc) : self { + foreach($this->_titles as $title) + $unimarc->zoneWithChildren('464', ['t' => $title]); + + return $this; + } + + + /** @test */ + public function pageShouldContainsSourceGamAnnecy() { + $this->assertXPathContentContains('//h3', 'Source : GAM Annecy'); + } + + + /** @test */ + public function pageShouldContainsAllTracks() { + $this->assertXPathCount('//li', count($this->_titles)); + } + + + /** @test */ + public function pageShouldContains5AudioPlayer() { + $this->assertXPathCount('//audio', 5); + } + + + public function tracksWithSample() { + return array_map(fn($k, $title) => [$k, $title], + array_keys($this->_titles_with_sample), + $this->_titles_with_sample); + } + + + /** + * @test + * @dataProvider tracksWithSample + */ + public function pageShouldContainsAudioPlayerFor(int $position, string $title) { + $this->assertXPathContentContains('//li//div[@class="notice_info_ligne"][following-sibling::audio//source[@src="https://www.gamannecy.com/' . $position . '.mp3"]]', + ($position + 1) . ': ' . $title); + } +} + + + + +abstract class NoticeAjaxControllerMorceauxBaseTestCase extends AbstractControllerTestCase { + public function setUp() { + parent::setUp(); + + $this->fixture(Class_TypeDoc::class, + ['id' => 8, + 'label' => 'mp3', + 'famille_id' => Class_CodifTypeDoc::SONORE]); + + $unimarc = (new Class_NoticeUnimarc_Fluent) + ->zoneWithContent('001', '104363') + ->zoneWithChildren('200', ['a' => 'Sur scène', + 'f' => 'Fredericks, Goldman, Jones']) + ->zoneWithChildren('710', ['a' => 'Fredericks, Goldman, Jones', + '4' => 590, + '6' => 'Interprète']) + ; + + $this->_addTrackTo($unimarc); + + $this->fixture(Class_Notice::class, + ['id' => 18238, + 'type_doc' => 8, + 'unimarc' => $unimarc->render()]); + + $this->dispatch('/opac/noticeajax/morceaux/id/18238'); + } + + + abstract protected function _addTrackTo(Class_NoticeUnimarc_Fluent $unimarc) : self; + + + /** @test */ + public function pageShouldContainsSourceBibliotheque() { + $this->assertXPathContentContains('//h3', utf8_encode('Source : Bibliothèque')); + } + + + /** @test */ + public function pageShouldContainsTrackNuit() { + $this->assertXPathContentContains('//li//div[@class="notice_info_ligne"]', + '1: Nuit / J.J. Goldman 2mn 39s'); + } +} + + + + +class NoticeAjaxControllerMorceauxBaseOn464_Dollar_A_Test + extends NoticeAjaxControllerMorceauxBaseTestCase { + + protected function _addTrackTo(Class_NoticeUnimarc_Fluent $unimarc) : self { + $unimarc->zoneWithChildren('464', ['a' => 'Nuit', + 'f' => 'Goldman', + 'g' => 'J.J.', + 'd' => '2mn 39s']); + return $this; + } + + + /** @test */ + public function pageShouldNotContainsVolumeInfo() { + $this->assertNotXPathContentContains('//div', 'Volume'); + } +} + + + + +class NoticeAjaxControllerMorceauxBaseOn464_Dollar_T_Test + extends NoticeAjaxControllerMorceauxBaseTestCase { + + protected function _addTrackTo(Class_NoticeUnimarc_Fluent $unimarc) : self { + $unimarc->zoneWithChildren('464', ['t' => 'Nuit', + 'a' => 'Goldman', + 'b' => 'J.J.', + 'd' => '2mn 39s']); + return $this; + } +} + + + + +class NoticeAjaxControllerMorceauxBaseOn464_Dollar_T_WithVolumesTest + extends NoticeAjaxControllerMorceauxBaseTestCase { + + protected function _addTrackTo(Class_NoticeUnimarc_Fluent $unimarc) : self { + $unimarc + ->zoneWithChildren('464', ['t' => 'Nuit', + 'a' => 'Goldman', + 'b' => 'J.J.', + 'd' => '2mn 39s', + 'v' => '1']) + ->zoneWithChildren('464', ['t' => 'Peurs', + 'a' => 'Goldman', + 'b' => 'J.J.', + 'd' => '3s', + 'v' => '2']); + return $this; + } + + + /** @test */ + public function pageShouldContainsTwoVolumesInfo() { + $this->assertXPathCount('//div[@class="notice_info_ligne_titre"][contains(text(), "Volume n")]', + 2); + } + + + /** @test */ + public function pageShouldContainsTrackPeursAsFirstTrackOfSecondVolume() { + $this->assertXPathContentContains('//li//div[@class="notice_info_ligne"]', + '1: Peurs / J.J. Goldman 3s'); + } +} diff --git a/tests/library/Class/NoticeTest.php b/tests/library/Class/NoticeTest.php index e52ff3a0d6e..bfa548b31a2 100644 --- a/tests/library/Class/NoticeTest.php +++ b/tests/library/Class/NoticeTest.php @@ -578,38 +578,44 @@ class NoticeTestTranslator extends ModelTestCase { abstract class NoticeThirdPartyTracksTestCase extends ModelTestCase { - protected $_tracks, $_result; + protected + $_tracks, + $_result; public function setUp() { parent::setUp(); - parent::setUp(); + $zone_995 = serialize( [ ['clef' => 'h', 'valeur' => '00510172'], ['clef' => '2', 'valeur' => '[AA][Adulte CEC][0][1][Disponible][0][0][0][0]']]); - $exemplaire = $this->fixture('Class_Exemplaire', + $exemplaire = $this->fixture(Class_Exemplaire::class, ['id' => 234, 'zone995' => $zone_995]); - $notice = $this->fixture('Class_Notice', + $notice = $this->fixture(Class_Notice::class, ['id' => 34, 'type_doc' => Class_TypeDoc::DISQUE, 'exemplaires' => [$exemplaire], 'unimarc' => file_get_contents(ROOT_PATH . '/tests/fixtures/' . $this->_unimarc)]); - $this->_result = $notice->getMorceaux(); - $this->_tracks = $this->_result['morceaux']; + $this->_result = Class_Notice_AudioTracks::newFor($notice); + $this->_tracks = $this->_result->collection()->getArrayCopy(); } protected function assertTitleAtEquals($position, $expected) { - $this->assertEquals($expected, $this->trackAt($position)['titre']); + $this->assertEquals($expected, + $this->trackAt($position)->getTitle(), + json_encode(array_map(fn($track) => $track->getTitle(), + $this->_tracks), + JSON_PRETTY_PRINT)); } protected function trackAt($position) { - return $this->_tracks[1][$position]; + return $this->_tracks[$position - 1]; } } @@ -622,13 +628,13 @@ class NoticeCvsTest extends NoticeThirdPartyTracksTestCase { /** @test */ public function sourceShouldBeCvs() { - $this->assertEquals('CVS', $this->_result['source']); + $this->assertEquals('CVS', $this->trackAt(1)->getSource()); } /** @test */ - public function shouldHave55TracksInVolume1() { - $this->assertEquals(55, count($this->_tracks[1])); + public function shouldHave55Tracks() { + $this->assertEquals(55, count($this->_tracks)); } @@ -640,7 +646,7 @@ class NoticeCvsTest extends NoticeThirdPartyTracksTestCase { /** @test */ public function firstTrackUrlShouldNotBePresent() { - $this->assertFalse(isset($this->trackAt(1)['url_ecoute'])); + $this->assertEquals('', $this->trackAt(1)->getUrl()); } @@ -651,9 +657,9 @@ class NoticeCvsTest extends NoticeThirdPartyTracksTestCase { /** @test */ - public function secondTrackUrlShouldBeAsExpected() { + public function secondTrackUrlShouldBeHomeSongexEtc() { $this->assertEquals('http://www.cvs-mediatheques.com/home/songex/0/251/861251/861251_1_1_x.mp3', - $this->trackAt(2)['url_ecoute']); + $this->trackAt(2)->getUrl()); } } @@ -666,13 +672,13 @@ class NoticeGamTest extends NoticeThirdPartyTracksTestCase { /** @test */ public function sourceShouldBeGamAnnecy() { - $this->assertEquals('GAM Annecy', $this->_result['source']); + $this->assertEquals('GAM Annecy', $this->trackAt(1)->getSource()); } /** @test */ - public function shouldHave12TracksInVolume1() { - $this->assertEquals(12, count($this->_tracks[1])); + public function shouldHave12Tracks() { + $this->assertEquals(12, count($this->_tracks)); } @@ -683,9 +689,9 @@ class NoticeGamTest extends NoticeThirdPartyTracksTestCase { /** @test */ - public function firstTrackUrlShouldNotBePresent() { + public function firstTrackUrlShouldBe01_5099973054320DotMp3() { $this->assertEquals('http://www.gamannecy.com/polysson/201203/01-5099973054320.mp3', - $this->trackAt(1)['url_ecoute']); + $this->trackAt(1)->getUrl()); } @@ -696,9 +702,9 @@ class NoticeGamTest extends NoticeThirdPartyTracksTestCase { /** @test */ - public function secondTrackUrlShouldBeAsExpected() { + public function secondTrackUrlShouldBe02_5099973054320DotMp3() { $this->assertEquals('http://www.gamannecy.com/polysson/201203/02-5099973054320.mp3', - $this->trackAt(2)['url_ecoute']); + $this->trackAt(2)->getUrl()); } @@ -710,7 +716,7 @@ class NoticeGamTest extends NoticeThirdPartyTracksTestCase { /** @test */ public function sixthTrackUrlShouldBeMissing() { - $this->assertFalse(isset($this->trackAt(6)['url_ecoute'])); + $this->assertEquals('', $this->trackAt(6)->getUrl()); } } @@ -723,13 +729,13 @@ class NoticeGamMusiqueAraboAndalouseTest extends NoticeThirdPartyTracksTestCase /** @test */ public function sourceShouldBeGamAnnecy() { - $this->assertEquals('GAM Annecy', $this->_result['source']); + $this->assertEquals('GAM Annecy', $this->trackAt(1)->getSource()); } /** @test */ - public function numberOfTracksshouldBeFive() { - $this->assertEquals(5, count($this->_tracks[1])); + public function numberOfTracksShouldBeFive() { + $this->assertEquals(5, count($this->_tracks)); } @@ -740,9 +746,9 @@ class NoticeGamMusiqueAraboAndalouseTest extends NoticeThirdPartyTracksTestCase /** @test */ - public function firstTrackShouldHaveUrlEcoute() { + public function firstTrackUrlShouldBe01_0794881648122DotMp3() { $this->assertEquals('https://www.gamannecy.com/polysson/201012/01-0794881648122.mp3', - $this->trackAt(1)['url_ecoute']); + $this->trackAt(1)->getUrl()); } } @@ -754,22 +760,25 @@ class NoticeStromaeTest extends ModelTestCase { public function setUp() { parent::setUp(); + $zone_995 = serialize( [ ['clef' => 'h', 'valeur' => '00510172'], ['clef' => '2', 'valeur' => '[AA][Adulte CEC][0][1][Disponible][0][0][0][0]']]); - $exemplaire = $this->fixture('Class_Exemplaire', + $exemplaire = $this->fixture(Class_Exemplaire::class, ['id' => 234, 'zone995' => $zone_995]); - $stromae = $this->fixture('Class_Notice', + $stromae = $this->fixture(Class_Notice::class, ['id' => 34, 'type_doc' => Class_TypeDoc::DISQUE, 'exemplaires' => [$exemplaire], 'unimarc' => '02077njm0 2200661 450 001000700000010001200007071002100019073001800040100004100058126001800099200001900117200001600136210003700152210000300189215003100192327030600223327000300529330030600532345000800838345002200846349002700868464000300895464000300898464000300901464000300904464000300907464000300910464000300913464000300916464000300919464000300922464000300925464000300928464000300931464001300934464001400947464001200961464001600973464002000989464001601009464001801025464001101043464002001054464001801074464001201092464001001104464003901114686003401153700001201187700000301199701000301202701000301205702001601208702001201224801002201236902000901258992014801267160553 d19,29 E01a3747987bMosaert a0602537479870 a20130916d2013 m y0frea0103 ba abxhx cd1 aRacine carrée1 bCDfStromae cUniversal Music France S.ad2013 1 1a1 disque compacte1 Livret aAprès son premier album \'\'Cheese\'\' paru en 2010, Stromae est de retour avec \'\'Racine carrée\'\', un album actuel, nomade et universel, écrit et composé aux quatre coins du monde sur un ordinateur portable. Stromae y applique sa recette singulière : poser des mots forts sur des beats irésistibles.1 aAprès son premier album \'\'Cheese\'\' paru en 2010, Stromae est de retour avec \'\'Racine carrée\'\', un album actuel, nomade et universel, écrit et composé aux quatre coins du monde sur un ordinateur portable. Stromae y applique sa recette singulière : poser des mots forts sur des beats irésistibles. aCVS b0602537479870cCD b3747987c06025374798701 1 1 1 1 1 1 1 1 1 1 1 1 tTa fête tPapaoutai tBâtard tAve Cesaria tTous les mêmes tFormidables tMoules frites tCarmen tHumain à l\'eau tQuand c\'est ? tSommeil tMerci fStromaegMaitre GimsgOrelsantAvf a8tChanson francophone2PCDM4 1aStromae 1 1 1 1aMaitre Gims 1aOrelsan 1aFRbCVSc20130916 a0997 uhttp://websvc.pergame.net/afi_opac_services/images/jaquettes/2/4/4/3/thumbs/2443329.jpegvhttp://ecx.images-amazon.com/images/I/51dXO1x36GL.jpg']); - $this->_tracks = $stromae->getMorceaux()['morceaux']; + $this->_tracks = Class_Notice_AudioTracks::newFor($stromae) + ->collection() + ->getArrayCopy(); $unimarc = Class_Exemplaire::find(234)->toUnimarcIso2709(); $this->_temp_file = tempnam('/tmp', 'UNIMARC'); @@ -808,13 +817,13 @@ class NoticeStromaeTest extends ModelTestCase { /** @test */ public function tracksShouldContainsTaFete() { - $this->assertEquals('Ta fête', $this->_tracks[1][1]['titre']); + $this->assertEquals('Ta fête', $this->_tracks[0]->getTitle()); } /** @test */ public function tracksShouldContainsPapaoutai() { - $this->assertEquals('Papaoutai', $this->_tracks[1][2]['titre']); + $this->assertEquals('Papaoutai', $this->_tracks[1]->getTitle()); } diff --git a/tests/scenarios/AlbumAudioRecord/AlbumAudioRecordTest.php b/tests/scenarios/AlbumAudioRecord/AlbumAudioRecordTest.php index 17061b35b04..290615cacbd 100644 --- a/tests/scenarios/AlbumAudioRecord/AlbumAudioRecordTest.php +++ b/tests/scenarios/AlbumAudioRecord/AlbumAudioRecordTest.php @@ -23,19 +23,19 @@ abstract class AlbumAudioRecordTestCase extends AbstractControllerTestCase { protected $_notice, - $_storm_default_to_volatile=true, - $_codif_auteur_wrapper; + $_codif_auteur_wrapper, + $_tracks; public function setUp() { parent::setUp(); - $_http_client = Storm_Test_ObjectWrapper::mock()->whenCalled('open_url')->answers(null); + $_http_client = $this->mock()->whenCalled('open_url')->answers(null); Class_WebService_AllServices::setHttpClient($_http_client); Class_Notice::setTimeSource(new TimeSourceForTest('2014-01-19 09:00:00')); - $this->_codif_auteur_wrapper = Storm_Test_ObjectWrapper::onLoaderOfModel('Class_CodifAuteur'); + $this->_codif_auteur_wrapper = $this->onLoaderOfModel(Class_CodifAuteur::class); Class_CosmoVar::newInstanceWithId('black_list_856', ['valeur' => 'mabib']); Class_CosmoVar::newInstanceWithId('unimarc_zone_titre', @@ -48,11 +48,11 @@ abstract class AlbumAudioRecordTestCase extends AbstractControllerTestCase { ->whenCalled('fetchAll')->answers([ [1, ''] ]); Zend_Registry::set('sql', $this->mock_sql); - $this->fixture('Class_CodifTypeDoc', + $this->fixture(Class_CodifTypeDoc::class, ['id' => Class_TypeDoc::AUDIO_RECORD, 'famille_id' => Class_CodifTypeDoc::SONORE]); - $album = $this->fixture('Class_Album', + $album = $this->fixture(Class_Album::class, ['id' => 4, 'type_doc_id' => Class_TypeDoc::AUDIO_RECORD, 'titre' => 'Seventh Son of a Seventh Son', @@ -67,18 +67,18 @@ abstract class AlbumAudioRecordTestCase extends AbstractControllerTestCase { $album ->setDistributor('Geffen Records') - ->addRessource($this->fixture('Class_AlbumRessource', + ->addRessource($this->fixture(Class_AlbumRessource::class, ['id' => 1, 'titre' => 'Moonchild', 'fichier' => 'moonchild.mp3'])) - ->addRessource($this->fixture('Class_AlbumRessource', + ->addRessource($this->fixture(Class_AlbumRessource::class, ['id' => 2, 'titre' => 'Infinite Dreams', 'fichier' => 'infinite_dreams.mp3'])) - ->addRessource($this->fixture('Class_AlbumRessource', + ->addRessource($this->fixture(Class_AlbumRessource::class, ['id' => 3, 'fichier' => 'unknown.mp3'])) - ->addRessource($this->fixture('Class_AlbumRessource', + ->addRessource($this->fixture(Class_AlbumRessource::class, ['id' => 4, 'fichier' => '502_05_the_prophecy.mp3'])); $album->getMarc() @@ -89,6 +89,9 @@ abstract class AlbumAudioRecordTestCase extends AbstractControllerTestCase { $album->index(); $this->_notice = Class_Exemplaire::findFirstBy(['id_origine' => 4])->getNotice(); + $this->_tracks = Class_Notice_AudioTracks::newFor($this->_notice) + ->collection() + ->getArrayCopy(); } @@ -124,7 +127,7 @@ class AlbumAudioRecordViewNoticeTest extends AlbumAudioRecordTestCase { ->whenCalled('fetchAll')->answers([ [1, ''] ]); Zend_Registry::set('sql', $this->mock_sql); - $this->dispatch('/recherche/viewnotice/id/'.$this->_notice->getId(), true); + $this->dispatch('/recherche/viewnotice/id/'.$this->_notice->getId()); } @@ -179,31 +182,28 @@ class AlbumAudioRecordViewNoticeTest extends AlbumAudioRecordTestCase { /** @test */ public function noticeFirstMorceauTitleShouldBeMoonchild() { - $this->assertEquals('Moonchild', - $this->_notice->getMorceaux()['morceaux'][1][1]['titre']); + $this->assertEquals('Moonchild', $this->_tracks[0]->getTitle()); } /** @test */ public function noticeFirstMorceauUrlEcouteShouldBeMoonchildDotMP3() { - $this->assertContains('/bib-numerique/play-ressource/id/1.mp3', - $this->_notice->getMorceaux()['morceaux'][1][1]['url_ecoute']); + $this->assertContains('/bib-numerique/play-ressource/id/1.mp3', $this->_tracks[0]->getUrl()); } /** @test */ public function noticeSecondMorceauTitleShouldBeInfiniteDreams() { - $this->assertEquals('Infinite Dreams', - $this->_notice->getMorceaux()['morceaux'][1][2]['titre']); + $this->assertEquals('Infinite Dreams', $this->_tracks[1]->getTitle()); } /** @test */ public function noticeUnknownMorceauTitleShouldBeUnknown() { - $this->assertEquals('Unknown', - $this->_notice->getMorceaux()['morceaux'][1][3]['titre']); + $this->assertEquals('Unknown', $this->_tracks[2]->getTitle()); } + /** @test */ public function titresFulltextShouldContainsMOONCHILD() { $this->assertContains('MOONCHILD', @@ -266,13 +266,13 @@ class AlbumAudioRecordViewNoticeTest extends AlbumAudioRecordTestCase { class AlbumAudioRecordViewMorceauxTest extends AlbumAudioRecordTestCase { public function setUp() { parent::setUp(); - $this->dispatch('/opac/noticeajax/morceaux/id_notice/' . $this->_notice->getId(), true); + $this->dispatch('/opac/noticeajax/morceaux/id_notice/' . $this->_notice->getId()); } /** @test */ public function moonchildPlayerShouldBePresent() { - $this->assertXPath('//audio/source[contains(@src, "/bib-numerique/play-ressource/id/1.mp3")]', $this->_response->getBody()); + $this->assertXPath('//audio/source[contains(@src, "/bib-numerique/play-ressource/id/1.mp3")]'); } @@ -288,6 +288,13 @@ class AlbumAudioRecordViewMorceauxTest extends AlbumAudioRecordTestCase { $this->assertXPathContentContains('//div[@class="notice_info_ligne"]', '2: Infinite Dreams'); } + + + /** @test */ + public function unknownTitleShouldBePresent() { + $this->assertXPathContentContains('//div[@class="notice_info_ligne"]', + '3: Unknown'); + } } diff --git a/tests/scenarios/Jamendo/JamendoTest.php b/tests/scenarios/Jamendo/JamendoTest.php index f3345bd20da..9cd585fc86a 100644 --- a/tests/scenarios/Jamendo/JamendoTest.php +++ b/tests/scenarios/Jamendo/JamendoTest.php @@ -169,6 +169,11 @@ class JamendoAlbumEcosTest extends JamendoTestCase{ public function setUp() { parent::setUp(); + $this->fixture(Class_TypeDoc::class, + ['id' => Class_TypeDoc::JAMENDO, + 'label' => 'audio', + 'famille_id' => Class_CodifTypeDoc::SONORE]); + $json = json_decode(file_get_contents(__DIR__.'/tracks_page_0.json')); $this->_album = (new Class_WebService_BibNumerique_Jamendo_Album($json->results[0]))->import(); $this->_album = Class_Album::find(1); @@ -215,16 +220,38 @@ class JamendoAlbumEcosTest extends JamendoTestCase{ /** @test */ - public function shouldBeAudioRecord() { + public function albumShouldBeAudioRecord() { $this->assertTrue($this->_album->isAudioRecord()); + } + + /** @test */ + public function noticeShouldBeTypeDocSonore() { + $this->assertTrue($this->_album->getNotice()->isTypeDocSonore()); } /** @test */ public function noticeShouldHaveThreeTracks() { - $this->assertCount(3, - $this->_album->getNotice()->getMorceaux()['morceaux'][1]); + $tracks = Class_Notice_AudioTracks::newFor($this->_album->getNotice())->collection(); + $this->assertEquals(3, $tracks->count()); + } + + + public function tracksTitles() : array { + return [['Ecos_de_mi'], + ['Alma'], + ['Al-otro-lado']]; + } + + + /** + * @test + * @dataProvider tracksTitles + */ + public function noticeShouldHaveTrack(string $title) { + $tracks = Class_Notice_AudioTracks::newFor($this->_album->getNotice())->collection(); + $this->assertNotNull($tracks->detect(fn($track) => $title == $track->getTitle())); } diff --git a/tests/scenarios/Templates/ChiliRecordMediaTest.php b/tests/scenarios/Templates/ChiliRecordMediaTest.php deleted file mode 100644 index e0343c17878..00000000000 --- a/tests/scenarios/Templates/ChiliRecordMediaTest.php +++ /dev/null @@ -1,176 +0,0 @@ -<?php -/** - * Copyright (c) 2012-2021, 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 ChiliRecordMediaDispatchTest extends AbstractControllerTestCase { - - protected $_storm_default_to_volatile = true; - - - public function setUp() { - parent::setUp(); - - $this->fixture(Class_TypeDoc::class, - ['id' => 3, - 'label' => 'disc', - 'famille_id' => Class_CodifTypeDoc::SONORE - ]); - - $unimarc = (new Class_NoticeUnimarc_Fluent) - ->zoneWithContent('001', '12345') - ->zoneWithChildren('200', ['f' => 'Loow']) - ->zoneWithChildren('464', ['t' => 'Lotus out of water', - '3' => 'https://my-super-sound/lotus_out_of_water.mp3']) - ->zoneWithChildren('464', ['t' => 'Milking song', - '3' => 'https://my-super-sound/milking_song.mp3']) - ->zoneWithChildren('464', ['t' => 'Boisson Divine', - '3' => 'https://youtube.com/watch?v=12341513O']) - ->zoneWithChildren('464', ['t' => 'Spirits From Tuva', - '3' => 'https://ma-discotheque.org/Hunn-Huur-Tu/song']); - - $record = $this->fixture(Class_Notice::class, - ['id' => 456, - 'titre_principal' => 'Beethoven pour les petits maestros', - 'unimarc' => $unimarc->render(), - 'type_doc' => 3, - 'clef_oeuvre' => 'BEETHOVEN', - 'url_vignette' => 'big_picture_300x300.jpg', - 'facettes' => 'T3 G13 M12']); - - $this->_buildTemplateProfil(['id' => 72, - 'template' => 'Chili']); - - $web_client = $this - ->mock()->beStrict() - - ->whenCalled('getResponse') - ->with('https://www.last.fm/music/Loow/+images/') - ->answers((new Class_Testing_HttpResponse)->setBody(' -<html lang="fr"> - <head></head> - <body> - <ul class="image-list"> - <li class="image-list-item"> - <a href="/music/Sh%C5%8D+Aimoto/+images/" class="image-list-link"> - <img class="image-list-image" - src="https://lastfm-img2.akamaized.net/i/u/avatar170s/big_picture_300x300.jpg" - alt="None"> - </a> - </li> - </ul> - </body> -</html>')); - - Intonation_Library_LastFm::setWebClient($web_client); - - Class_CosmoVar::setValueOf('url_services', 'https://cache-server.org'); - - Class_WebService_Afi::setHttpClient($this - ->mock() - ->whenCalled('open_url') - ->answers(json_encode(['source' => 'testing', - 'player' => '<iframe src="https://www.super-trailers.org/?media=18397590" style="width:500px; height:400px" frameborder="0"></iframe>']))); - - $this->dispatch('/opac/noticeajax/media/id/456'); - } - - - public function tearDown() { - Intonation_Library_LastFm::setWebClient(null); - parent::tearDown(); - } - - - /** @test */ - public function milkingSongShouldBeDisplayAsATrack() { - $this->assertXPathContentContains('//div[@class="list-group bg-transparent no_border"]//a[@data-track-url = "https://my-super-sound/milking_song.mp3"]//span[@class = "track_title"]', 'Milking song'); - } - - - /** @test */ - public function spiritsFromTuvaShouldBeDisplayAsTrack() { - $this->assertXPathContentContains('//div[@class="list-group bg-transparent no_border"]//a[@data-track-url = "https://ma-discotheque.org/Hunn-Huur-Tu/song"]//span[@class = "track_title"]', 'Spirits From Tuva'); - } - - - /** @test */ - public function lotusOutOfWaterSongShouldBeDisplayAsYoutube() { - $this->assertXPathContentContains('//div[@class="list-group bg-transparent no_border"]//a[@data-track-url = "https://my-super-sound/lotus_out_of_water.mp3"][contains(@onclick, "$(\'.audio_player\').attr(\'src\',$(this).attr(\'data-track-url\'));")]//span[@class = "track_title"][following-sibling::span[@class="track_source"][text()="CVS"]]', 'Lotus out of water'); - } - - - /** @test */ - public function playerShouldBePresent() { - $this->assertXPath('//audio'); - } - - - /** @test */ - public function trailersShouldBeInWall() { - $this->assertXPath('//div[@class="masonry-content"]//iframe[@src = "https://www.super-trailers.org/?media=18397590"]'); - } - - - /** @test */ - public function boissonDivineShouldBeInSeparateList() { - $this->assertXPathContentContains('//div[contains(@class,"youtube_tracks")]//span', 'Boisson Divine'); - } - - - /** @test */ - public function boissionDivineIframeShouldBePresent() { - $this->assertXPath('//div[contains(@class,"youtube_tracks")]//iframe[@src = "https://youtube.com/watch?v=12341513O"]'); - } -} - - - -class ChiliRecordMediaDispatchWithEmptyMessageTest extends AbstractControllerTestCase { - - public function setUp() { - parent::setUp(); - - $this->fixture(Class_Notice::Class, - ['id' => 456, - 'titre_principal' => 'Beethoven pour les petits maestros', - 'type_doc' => 1, - 'clef_oeuvre' => 'BEETHOVEN', - 'url_vignette' => 'big_picture_300x300.jpg', - 'facettes' => 'T3 G13 M12']); - - $this->_buildTemplateProfil(['id' => 72, - 'template' => 'Chili']); - - $this->dispatch('/opac/noticeajax/media/id/456'); - } - - - /** @test */ - public function emptyWallFirtItemShouldBePresent() { - $this->assertXPath('//div[@class="masonry-content"]//div[@class = "empty_media empty_media_first_item"]'); - } - - - /** @test */ - public function fiveEmptyMediaShouldBePresent() { - $this->assertXPathCount('//div[@class="masonry-content"]//div[contains(@class, "empty_media")]', 5); - } -} diff --git a/tests/scenarios/Templates/TemplatesDigitalResourcesTest.php b/tests/scenarios/Templates/TemplatesDigitalResourcesTest.php index a5e87d7a596..bc76d02ea19 100644 --- a/tests/scenarios/Templates/TemplatesDigitalResourcesTest.php +++ b/tests/scenarios/Templates/TemplatesDigitalResourcesTest.php @@ -289,21 +289,11 @@ abstract class TemplatesDigitalResourcesTrailerAdministrationTestCase ->answers(json_encode(['source' => 'test_bokeh', 'disable_trailer' => $this->_is_trailer_disabled, 'player' => '<iframe src="https://www.super-trailers.org/?media=18397590" style="width:500px; height:400px" frameborder="0"></iframe>']))); - - Intonation_Library_LastFm::setWebClient($this->mock() - ->whenCalled('getResponse') - ->with('https://www.last.fm/music/M./Psycho') - ->answers('') - - ->whenCalled('getResponse') - ->with('https://www.last.fm/music/M./+images/') - ->answers('')); } public function tearDown() { Class_WebService_Afi::setHttpClient(null); - Intonation_Library_LastFm::setWebClient(null); parent::tearDown(); } } diff --git a/tests/scenarios/Templates/TemplatesJumbotronTest.php b/tests/scenarios/Templates/TemplatesJumbotronTest.php index 1fe7ddbe150..930015fb655 100644 --- a/tests/scenarios/Templates/TemplatesJumbotronTest.php +++ b/tests/scenarios/Templates/TemplatesJumbotronTest.php @@ -20,10 +20,7 @@ */ -class TemplatesRecordsDispatchItemsTest extends AbstractControllerTestCase { - - protected $_storm_default_to_volatile = true; - +class TemplatesJumbotronRecordsItemsTest extends AbstractControllerTestCase { public function setUp() { parent::setUp(); diff --git a/tests/scenarios/Templates/TemplatesMediaTest.php b/tests/scenarios/Templates/TemplatesMediaTest.php new file mode 100644 index 00000000000..e32739d6429 --- /dev/null +++ b/tests/scenarios/Templates/TemplatesMediaTest.php @@ -0,0 +1,447 @@ +<?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 TemplatesMediaTestCase extends AbstractControllerTestCase { + public function setUp() { + parent::setUp(); + $this->_buildTemplateProfil(['id' => 72]); + + $this->fixture(Class_TypeDoc::class, + ['id' => 8, + 'label' => 'mp3', + 'famille_id' => Class_CodifTypeDoc::SONORE]); + } +} + + + + +abstract class TemplatesMediaRecordWithBaseTracksTestCase extends TemplatesMediaTestCase { + public function setUp() { + parent::setUp(); + + $unimarc = (new Class_NoticeUnimarc_Fluent) + ->zoneWithContent('001', '12345') + ->zoneWithChildren('200', ['a' => 'Psycho']) + ->zoneWithChildren('464', ['t' => 'Lotus out of water', + '3' => 'https://my-super-sound/1.mp3']) + ->zoneWithChildren('464', ['t' => 'Milking song', + '3' => 'https://my-super-sound/2.mp3']) + ->zoneWithChildren('700', ['a' => 'JM', 'b' => 'Big']) + ; + + $this->fixture(Class_Notice::class, + ['id' => 456, + 'unimarc' => $unimarc->render(), + 'type_doc' => 8, + 'clef_oeuvre' => 'PSYKO', + 'url_vignette' => 'big_picture_300x300.jpg', + 'facettes' => 'G13 M12']); + } +} + + + + +class TemplatesMediaRecordWithBaseTracksTest + extends TemplatesMediaRecordWithBaseTracksTestCase { + + public function setUp() { + parent::setUp(); + $this->dispatch('/opac/record/media/id/456/id_profil/72'); + } + + + /** @test */ + public function navLinkToRecordResumeShoulBeActive() { + $this->assertXPath('//ul[contains(@class, "nav-tabs")]//li/a[contains(@href, "record/media")][contains(@class, "active")]'); + } + + + /** @test */ + public function bigPictureShouldContainsAlt() { + $this->assertXPath('//div//img[contains(@src, "big_picture_300x300")][@alt="Couverture de Psycho"]'); + } + + + /** @test */ + public function pageShouldBeHtml5Valid() { + $this->assertHTML5(); + } + + + /** @test */ + public function pageShouldBeAccessible() { + $this->assertAccessible(false); + } +} + + + + +class TemplatesMediaNoticeajaxRecordWithBaseTracksTest + extends TemplatesMediaRecordWithBaseTracksTestCase { + + + public function setUp() { + parent::setUp(); + $this->dispatch('/opac/noticeajax/media/id/456/id_profil/72'); + } + + + /** @test */ + public function shouldRenderListGroupItemWithDataTrackUrl() { + $this->assertXPath('//div[contains(@class, "list-group-item")]//a[@data-track-url]'); + } + + + /** @test */ + public function shouldContainsOneAudio() { + $this->assertXPathCount('//audio', 1); + } +} + + + + +class TemplatesMediaRecordWithGamTracksTest extends TemplatesMediaTestCase { + public function possibleZones() : array { + return [['958'], + ['964'], + ['985'], + ['858']]; + } + + + /** + * @test + * @dataProvider possibleZones + */ + public function shouldDisplayMediaFromZone(string $zone) { + $this->_fixtureRecordWithZone($zone); + $this->dispatch('/noticeajax/tracks/id/456/id_profil/72'); + $this->assertXPathContentContains('//a[contains(@class, "audio_track")][@data-track-url="https://my-super-sound/1.mp3"]', + 'If eternity should fail'); + } + + + /** + * @test + * @dataProvider possibleZones + */ + public function pageShouldContainsOneAudioPlayer(string $zone) { + $this->_fixtureRecordWithZone($zone); + $this->dispatch('/noticeajax/tracks/id/456/id_profil/72'); + $this->assertXPathCount('//audio', 1); + } + + + /** + * @test + * @dataProvider possibleZones + */ + public function pageShouldSourceGamHeader(string $zone) { + $this->_fixtureRecordWithZone($zone); + $this->dispatch('/noticeajax/tracks/id/456/id_profil/72'); + $this->assertXPathContentContains('//h3[contains(@class, "tracks_source")]', + 'Source : GAM Annecy'); + } + + + protected function _fixtureRecordWithZone(string $zone) : self { + $unimarc = (new Class_NoticeUnimarc_Fluent) + ->zoneWithContent('001', '12345') + ->zoneWithChildren('200', ['f' => 'Iron Maiden']) + ->zoneWithChildren('461', ['t' => 'The book of souls']) + ->zoneWithChildren('801', ['b' => 'GAM']) + ->zoneWithChildren('464', ['t' => 'If eternity should fail']) + + ->zoneWithChildren($zone, ['u' => 'https://my-super-sound/1.mp3', + 'z' => 'If eternity should fail']) + ; + + $this->fixture(Class_Notice::class, + ['id' => 456, + 'unimarc' => $unimarc->render(), + 'type_doc' => 8, + 'clef_oeuvre' => 'THE BOOK OF SOULS', + 'facettes' => 'G13 M12']); + + return $this; + } +} + + + + +class TemplatesMediaRecordWithCVSTracksTest extends TemplatesMediaTestCase { + public function setUp() { + parent::setUp(); + $unimarc = (new Class_NoticeUnimarc_Fluent) + ->zoneWithContent('001', '12345') + + ->zoneWithChildren('200', ['f' => 'Iron Maiden']) + + ->zoneWithChildren('461', ['t' => 'The book of souls']) + + ->zoneWithChildren('801', ['b' => 'CVS']) + + ->zoneWithChildren('464', ['t' => 'If eternity should fail']) + ->zoneWithChildren('856', ['u' => 'https://my-super-sound/1.mp3', + 'a' => 'If eternity should fail']); + + $this->fixture(Class_Notice::class, + ['id' => 456, + 'unimarc' => $unimarc->render(), + 'type_doc' => 8, + 'clef_oeuvre' => 'THE BOOK OF SOULS', + 'facettes' => 'G13 M12']); + + $this->dispatch('/noticeajax/tracks/id/456/id_profil/72'); + } + + + /** @test */ + public function pageShouldContainIfEternityShouldFailTrack() { + $this->assertXPathContentContains('//a[contains(@class, "audio_track")][@data-track-url="https://my-super-sound/1.mp3"]', + 'If eternity should fail'); + } + + + /** @test */ + public function pageshouldContainAudioPlayer() { + $this->assertXPath('//audio[@class="audio_player"]'); + } + + + /** @test */ + public function pageShouldContainSourceCVSHeader() { + $this->assertXPathContentContains('//h3[contains(@class, "tracks_source")][contains(@class, "d-none")]', + 'Source : CVS'); + } +} + + + + +class TemplatesMediaChiliNoticeajaxRecordWithBaseTracksTest extends TemplatesMediaTestCase { + public function setUp() { + parent::setUp(); + + $unimarc = (new Class_NoticeUnimarc_Fluent) + ->zoneWithContent('001', '12345') + ->zoneWithChildren('200', ['f' => 'Loow']) + ->zoneWithChildren('464', ['t' => 'Lotus out of water', + '3' => 'https://my-super-sound/lotus_out_of_water.mp3']) + ->zoneWithChildren('464', ['t' => 'Milking song', + '3' => 'https://my-super-sound/milking_song.mp3']) + ->zoneWithChildren('464', ['t' => 'Boisson Divine', + '3' => 'https://youtube.com/watch?v=12341513O']) + ->zoneWithChildren('464', ['t' => 'Spirits From Tuva', + '3' => 'https://ma-discotheque.org/Hunn-Huur-Tu/song']); + + $record = $this->fixture(Class_Notice::class, + ['id' => 456, + 'titre_principal' => 'Beethoven pour les petits maestros', + 'unimarc' => $unimarc->render(), + 'type_doc' => 3, + 'clef_oeuvre' => 'BEETHOVEN', + 'url_vignette' => 'big_picture_300x300.jpg', + 'facettes' => 'T3 G13 M12']); + + $this->_buildTemplateProfil(['id' => 72, + 'template' => 'Chili']); + + Class_CosmoVar::setValueOf('url_services', 'https://cache-server.org'); + + Class_WebService_Afi::setHttpClient($this + ->mock() + ->whenCalled('open_url') + ->answers(json_encode(['source' => 'testing', + 'player' => '<iframe src="https://www.super-trailers.org/?media=18397590" style="width:500px; height:400px" frameborder="0"></iframe>']))); + + $this->dispatch('/opac/noticeajax/media/id/456'); + } + + + /** @test */ + public function milkingSongShouldBeDisplayAsATrack() { + $this->assertXPathContentContains('//div[@class="list-group bg-transparent no_border"]//a[@data-track-url = "https://my-super-sound/milking_song.mp3"]//span[@class = "track_title"]', 'Milking song'); + } + + + /** @test */ + public function spiritsFromTuvaShouldBeDisplayAsTrack() { + $this->assertXPathContentContains('//div[@class="list-group bg-transparent no_border"]//a[@data-track-url = "https://ma-discotheque.org/Hunn-Huur-Tu/song"]//span[@class = "track_title"]', 'Spirits From Tuva'); + } + + + /** @test */ + public function lotusOutOfWaterSongShouldBeDisplayAsYoutube() { + $this->assertXPathContentContains('//div[@class="list-group bg-transparent no_border"]//a[@data-track-url="https://my-super-sound/lotus_out_of_water.mp3"][contains(@onclick, "$(\'.audio_player\').attr(\'src\',$(this).attr(\'data-track-url\'));")]//span[@class="track_title"]', 'Lotus out of water'); + } + + + /** @test */ + public function playerShouldBePresent() { + $this->assertXPath('//audio'); + } + + + /** @test */ + public function trailersShouldBeInWall() { + $this->assertXPath('//div[@class="masonry-content"]//iframe[@src="https://www.super-trailers.org/?media=18397590"]'); + } + + + /** @test */ + public function boissonDivineShouldBeInSeparateList() { + $this->assertXPathContentContains('//div[contains(@class,"youtube_tracks")]//span', + 'Boisson Divine'); + } + + + /** @test */ + public function boissionDivineIframeShouldBePresent() { + $this->assertXPath('//div[contains(@class,"youtube_tracks")]//iframe[@src="https://youtube.com/watch?v=12341513O"]'); + } +} + + + + +class TemplaitsMediaChiliRecordWithoutTracksTest extends TemplatesMediaTestCase { + public function setUp() { + parent::setUp(); + + $record = $this->fixture(Class_Notice::class, + ['id' => 456, + 'titre_principal' => 'Beethoven pour les petits maestros', + 'type_doc' => 1, + 'clef_oeuvre' => 'BEETHOVEN', + 'url_vignette' => 'big_picture_300x300.jpg', + 'facettes' => 'T3 G13 M12']); + + $this->_buildTemplateProfil(['id' => 72, + 'template' => 'Chili']); + + $this->dispatch('/opac/noticeajax/media/id/456'); + } + + + /** @test */ + public function emptyWallFirstItemShouldBePresent() { + $this->assertXPath('//div[@class="masonry-content"]//div[@class = "empty_media empty_media_first_item"]'); + } + + + /** @test */ + public function fiveEmptyMediaShouldBePresent() { + $this->assertXPathCount('//div[@class="masonry-content"]//div[contains(@class, "empty_media")]', 5); + } +} + + + + +class TemplatesMediaRecordWithBaseTracksWithoutSampleTest extends TemplatesMediaTestCase { + public function setUp() { + parent::setUp(); + + $unimarc = (new Class_NoticeUnimarc_Fluent) + ->zoneWithContent('001', '12345') + ->zoneWithChildren('200', ['a' => 'Psycho']) + ->zoneWithChildren('464', ['t' => 'Lotus out of water']) + ->zoneWithChildren('464', ['t' => 'Milking song']) + ->zoneWithChildren('700', ['a' => 'JM', 'b' => 'Big']) + ; + + $this->fixture(Class_Notice::class, + ['id' => 456, + 'unimarc' => $unimarc->render(), + 'type_doc' => 8, + 'clef_oeuvre' => 'PSYKO', + 'url_vignette' => 'big_picture_300x300.jpg', + 'facettes' => 'G13 M12']); + } + + + /** @test */ + public function mediaPageShouldBeEmpty() { + $this->dispatch('/noticeajax/media/id/456'); + $this->assertEmpty($this->_response->getBody()); + } + + + /** @test */ + public function tracksPageShouldNotContainsLotusOutOfWater() { + $this->dispatch('/noticeajax/tracks/id/456'); + $this->assertNotXPathContentContains('//div', 'Lotus out of water'); + } + + + /** @test */ + public function tracksPageShouldNotContainsMilkingSong() { + $this->dispatch('/noticeajax/tracks/id/456'); + $this->assertNotXPathContentContains('//div', 'Milking song'); + } +} + + + + +class TemplatesMediaRecordWithBaseTracksWithIncompleteSampleTest extends TemplatesMediaTestCase { + public function setUp() { + parent::setUp(); + + $unimarc = (new Class_NoticeUnimarc_Fluent) + ->zoneWithContent('001', '12345') + ->zoneWithChildren('200', ['a' => 'Psycho']) + ->zoneWithChildren('464', ['t' => 'Lotus out of water']) + ->zoneWithChildren('464', ['t' => 'Milking song', + '3' => 'https://samplemusic.org/1.mp3']) + ->zoneWithChildren('700', ['a' => 'JM', 'b' => 'Big']) + ; + + $this->fixture(Class_Notice::class, + ['id' => 456, + 'unimarc' => $unimarc->render(), + 'type_doc' => 8, + 'clef_oeuvre' => 'PSYKO', + 'url_vignette' => 'big_picture_300x300.jpg', + 'facettes' => 'G13 M12']); + } + + + /** @test */ + public function pageShouldContainsMilkingSong() { + $this->dispatch('/noticeajax/media/id/456'); + $this->assertXPathContentContains('//div', 'Milking song'); + } + + + /** @test */ + public function pageShouldNotContainsLotusOutOfWater() { + $this->dispatch('/noticeajax/media/id/456'); + $this->assertNotXPathContentContains('//div', 'Lotus out of water'); + } +} diff --git a/tests/scenarios/Templates/TemplatesTest.php b/tests/scenarios/Templates/TemplatesTest.php index 33a83d71f0a..d225effb1c3 100644 --- a/tests/scenarios/Templates/TemplatesTest.php +++ b/tests/scenarios/Templates/TemplatesTest.php @@ -502,6 +502,12 @@ class TemplatesDispatchIntonationTest extends TemplatesIntonationTestCase { } + /** @test */ + public function subMenuAgendaShouldBeDisplay() { + $this->assertXPathContentContains('//div[contains(@class, "button_text")]', 'agenda'); + } + + /** @test */ public function buttonClassShouldContainsBtnBtnSecondary() { $this->assertXPath('//button[contains(@class, "btn btn-secondary")]'); @@ -1266,125 +1272,6 @@ class TemplatesRecordResumeDispatchTest extends TemplatesIntonationTestCase { -class TemplatesRecordMediaDispatchTest extends TemplatesIntonationTestCase { - public function setUp() { - parent::setUp(); - - $this->fixture('Class_TypeDoc', - ['id' => 8, - 'label' => 'mp3', - 'famille_id' => Class_CodifTypeDoc::SONORE - ]); - - $unimarc = (new Class_NoticeUnimarc_Fluent) - ->zoneWithContent('001', '12345') - ->zoneWithChildren('464', ['t' => 'Lotus out of water', - '3' => 'https://my-super-sound/1.mp3']) - ->zoneWithChildren('464', ['t' => 'Milking song', - '3' => 'https://my-super-sound/2.mp3']); - - $record = $this->fixture('Class_Notice', - ['id' => 456, - 'unimarc' => $unimarc->render(), - 'type_doc' => 8, - 'clef_oeuvre' => 'PSYKO', - 'url_vignette' => 'big_picture_300x300.jpg', - 'facettes' => 'G13 M12']) - ->setTitrePrincipal('Psycho'); - - $this->dispatch('/opac/record/media/id/456/id_profil/72'); - } - - - /** @test */ - public function navLinkToRecordResumeShoulBeActive() { - $this->assertXPath('//ul[contains(@class, "nav-tabs")]//li/a[contains(@href, "record/media")][contains(@class, "active")]'); - } - - - /** @test */ - public function bigPictureShouldContainsAlt() { - $this->assertXPath('//div//img[contains(@src, "big_picture_300x300")][@alt="Couverture de Psycho"]'); - } - - - /** @test */ - public function subMenuAgendaShouldBeDisplay() { - $this->assertXPathContentContains('//div[contains(@class, "button_text")]', 'agenda'); - } - - - /** @test */ - public function pageShouldBeHtml5Valid() { - $this->assertHTML5(); - } - - - /** @test */ - public function pageShouldBeAccessible() { - $this->assertAccessible(false,$this->_response->getBody()); - } -} - - - - -class TemplatesDispatchNoticeAjaxTracksTest extends TemplatesIntonationTestCase { - - /** @test */ - public function shouldDisplayAudio() { - $this->fixture('Class_TypeDoc', - ['id' => 8, - 'label' => 'mp3', - 'famille_id' => Class_CodifTypeDoc::SONORE - ]); - - $unimarc = (new Class_NoticeUnimarc_Fluent) - ->zoneWithContent('001', '12345') - - ->zoneWithChildren('200', ['f' => 'Iron Maiden']) - - ->zoneWithChildren('461', ['t' => 'The book of souls']) - - ->zoneWithChildren('801', ['b' => 'GAM']) - ->zoneWithChildren('464', ['t' => 'If eternity should fail']) - ->zoneWithChildren('856', ['u' => 'https://my-super-sound/1.mp3', - 'z' => 'If eternity should fail']) - ->zoneWithChildren('464', ['t' => 'Speed of light', - '3' => 'https://my-super-sound/2.mp3']); - - $record = $this->fixture('Class_Notice', - ['id' => 456, - 'unimarc' => $unimarc->render(), - 'type_doc' => 8, - 'clef_oeuvre' => 'THE BOOK OF SOULS', - 'facettes' => 'G13 M12']); - - $web_client = $this - ->mock()->beStrict() - - ->whenCalled('getResponse') - ->with('https://www.last.fm/music/Iron+Maiden/The+book+of+souls') - ->answers(new Class_Testing_HttpResponse) - ; - - Intonation_Library_LastFm::setWebClient($web_client); - - $this->dispatch('/noticeajax/tracks/id/456/id_profil/72'); - $this->assertXPath('//div//audio'); - } - - - public function tearDown() { - Intonation_Library_LastFm::setWebClient(null); - parent::tearDown(); - } -} - - - - - class TemplatesDispatchRecordDescriptionTest extends TemplatesIntonationTestCase { public function setUp() { @@ -1519,54 +1406,6 @@ class TemplatesDispatchRecordAuthorTest extends TemplatesIntonationTestCase { -class TemplatesNoticeajaxMediaDispatchTest extends TemplatesIntonationTestCase { - public function setUp() { - parent::setUp(); - - $this->fixture('Class_TypeDoc', - ['id' => 8, - 'label' => 'mp3', - 'famille_id' => Class_CodifTypeDoc::SONORE - ]); - - $unimarc = (new Class_NoticeUnimarc_Fluent) - ->zoneWithContent('001', '12345') - ->zoneWithChildren('464', ['t' => 'Lotus out of water', - '3' => 'https://my-super-sound/1.mp3']) - ->zoneWithChildren('464', ['t' => 'Milking song', - '3' => 'https://my-super-sound/2.mp3']); - - $record = $this->fixture('Class_Notice', - ['id' => 456, - 'titre_principal' => 'Psycho', - 'unimarc' => $unimarc->render(), - 'type_doc' => 8, - 'clef_oeuvre' => 'PSYKO', - 'url_vignette' => 'big_picture_300x300.jpg', - 'facettes' => 'G13 M12']); - - $this->dispatch('/opac/noticeajax/media/id/456/id_profil/72'); - } - - - /** @test */ - public function shouldRenderListGroupItemWithDataTrackUrl() { - $this->assertXPath('//div[contains(@class, "list-group-item")]//a[@data-track-url]'); - } - - - /** @test */ - public function shouldContainsOneAudio() { - $this->assertXPathCount('//audio', 1); - } -} - - - - - - - class TemplatesDispatchIntonationChangeIconAccountTest extends TemplatesIntonationTestCase { -- GitLab