diff --git a/VERSIONS_HOTLINE/192556 b/VERSIONS_HOTLINE/192556 new file mode 100644 index 0000000000000000000000000000000000000000..db778994f83c07c2d16fbb4b8c4d053b5aa8b97e --- /dev/null +++ b/VERSIONS_HOTLINE/192556 @@ -0,0 +1 @@ + - correctif #192556 : Abonné : Correctif la suppression d'une notice d'un panier ne fonctionnait pas quand cette notice était lié à des ressources numériques. \ No newline at end of file diff --git a/library/Class/PanierNotice/RecordKeys.php b/library/Class/PanierNotice/RecordKeys.php index 3b2baeedf9e75e3d6257fc9364436341610fc408..3fec288fb798d4f087306be30a50a8c797380bcb 100644 --- a/library/Class/PanierNotice/RecordKeys.php +++ b/library/Class/PanierNotice/RecordKeys.php @@ -20,15 +20,17 @@ */ -class Class_PanierNotice_RecordKeys { +class Class_PanierNotice_RecordKeys +{ + const KEY_SEPARATOR = ';'; protected static $_panier_record_keys_cache = []; protected array $_keys = []; - - public function __construct(Class_PanierNotice $selection) { + public function __construct(Class_PanierNotice $selection) + { $keys = array_map('trim', explode(static::KEY_SEPARATOR, $selection->getNotices())); $keys = array_filter(array_values(array_unique($keys))); @@ -37,13 +39,15 @@ class Class_PanierNotice_RecordKeys { } - public function add(Class_Notice $record) : string { + public function add(Class_Notice $record): string + { $this->_keys[] = $this->_keyFor($record); return $this->serialized(); } - public function remove(Class_Notice $record) : string { + public function remove(Class_Notice $record): string + { $record_key = $this->_keyFor($record); $this->_keys = array_filter($this->_keys, fn($key) => !$key->isSameAs($record_key)); @@ -52,13 +56,15 @@ class Class_PanierNotice_RecordKeys { } - public function keys() : array { + public function keys(): array + { return array_map(fn($key) => $key->keyOnly(), $this->_keys); } - public function contains(Class_Notice $record) : bool { + public function contains(Class_Notice $record): bool + { $record_key = $this->_keyFor($record); return 0 < count(array_filter($this->_keys, @@ -66,14 +72,16 @@ class Class_PanierNotice_RecordKeys { } - public function serialized() : string { + public function serialized(): string + { return implode(static::KEY_SEPARATOR, array_map(fn($key) => $key->serialized(), $this->_keys)); } - protected function _keyFor(Class_Notice $record) : Class_PanierNotice_RecordKey { + protected function _keyFor(Class_Notice $record): Class_PanierNotice_RecordKey + { $record_id = $record->getId(); if (isset(static::$_panier_record_keys_cache [$record_id])) return static::$_panier_record_keys_cache [$record_id]; @@ -82,7 +90,8 @@ class Class_PanierNotice_RecordKeys { } - public static function reset() { + public static function reset() + { static::$_panier_record_keys_cache = []; } } @@ -90,14 +99,16 @@ class Class_PanierNotice_RecordKeys { -abstract class Class_PanierNotice_RecordKey { +abstract class Class_PanierNotice_RecordKey +{ + const MODEL_SEPARATOR = '/'; const ID_SEPARATOR = '@'; protected string $_key; - - public static function newFromKey(string $key) : self { + public static function newFromKey(string $key): self + { $parts = explode(static::MODEL_SEPARATOR, $key); return (1 === count($parts)) ? static::_newExternal($key) @@ -105,7 +116,8 @@ abstract class Class_PanierNotice_RecordKey { } - public static function newFromRecord(Class_Notice $record) : self { + public static function newFromRecord(Class_Notice $record): self + { $key = $record->getClefAlpha(); return ($model = static::_detectModel($record)) @@ -114,8 +126,9 @@ abstract class Class_PanierNotice_RecordKey { } - protected static function _detectModel(Class_Notice $record) : ?Storm_Model_Abstract { - foreach(['getAlbum', 'getArticle', 'getPage', 'getSite', 'getRss'] as $method) + protected static function _detectModel(Class_Notice $record): ?Storm_Model_Abstract + { + foreach (['getAlbum', 'getArticle', 'getPage', 'getSite', 'getRss'] as $method) if ($model = $record->$method()) return $model; @@ -123,27 +136,32 @@ abstract class Class_PanierNotice_RecordKey { } - protected static function _newInternal(array $parts) : Class_PanierNotice_RecordKeyInternal { + protected static function _newInternal(array $parts): Class_PanierNotice_RecordKeyInternal + { return new Class_PanierNotice_RecordKeyInternal($parts); } - protected static function _newExternal(string $key) : Class_PanierNotice_RecordKeyExternal { + protected static function _newExternal(string $key): Class_PanierNotice_RecordKeyExternal + { return new Class_PanierNotice_RecordKeyExternal($key); } - public function serialized() : string { + public function serialized(): string + { return $this->_key; } - public function keyOnly() : string { + public function keyOnly(): string + { return $this->_key; } - public function isSameAs(Class_PanierNotice_RecordKey $other) : bool { + public function isSameAs(Class_PanierNotice_RecordKey $other): bool + { return $this->_key === $other->_key; } } @@ -151,9 +169,11 @@ abstract class Class_PanierNotice_RecordKey { -class Class_PanierNotice_RecordKeyExternal extends Class_PanierNotice_RecordKey { +class Class_PanierNotice_RecordKeyExternal extends Class_PanierNotice_RecordKey +{ - public function __construct(string $key) { + public function __construct(string $key) + { if (Class_Notice::countBy(['clef_alpha' => $key])) { $this->_key = $key; return; @@ -168,11 +188,14 @@ class Class_PanierNotice_RecordKeyExternal extends Class_PanierNotice_RecordKey -class Class_PanierNotice_RecordKeyInternal extends Class_PanierNotice_RecordKey { +class Class_PanierNotice_RecordKeyInternal extends Class_PanierNotice_RecordKey +{ - protected string $_model_info; + protected string $_model_info = ''; + protected bool $_with_model_info = false; - public function __construct(array $parts) { + public function __construct(array $parts) + { $this->_key = $parts[0] ?? ''; $this->_model_info = $parts[1] ?? ''; @@ -183,21 +206,49 @@ class Class_PanierNotice_RecordKeyInternal extends Class_PanierNotice_RecordKey if (2 !== count($model_parts)) return; - try { - $model_class = $model_parts[0] ?? ''; - $model_id = $model_parts[1] ?? 0; - if ($model_id && $model = $model_class::find($model_id)) - $this->_key = (new Class_Notice_ClefAlpha($model))->keyString(); - } catch(Exception $e) {} + $this->_keyForModelParts($model_parts); } - public function serialized() : string { + public function serialized(): string + { return parent::serialized() . static::MODEL_SEPARATOR . $this->_model_info; } - public function isSameAs(Class_PanierNotice_RecordKey $other) : bool { - return isset($other->_model_info) && $this->_model_info === $other->_model_info; + public function isSameAs(Class_PanierNotice_RecordKey $other): bool + { + return $this->_with_model_info + ? parent::isSameAs($other) && $this->_model_info === $other->_model_info + : parent::isSameAs($other); + } + + + protected function _keyForModelParts(array $model_parts): self + { + $model_class = $model_parts[0] ?? ''; + $model_id = $model_parts[1] ?? 0; + + if ($model = $this->_findForClassNameWithId($model_id, $model_class)) { + $this->_key = (new Class_Notice_ClefAlpha($model))->keyString(); + $this->_with_model_info = true; + } + + return $this; + } + + + protected function _findForClassNameWithId(int $id, string $class_name): ?Storm_Model_Abstract + { + if ( ! $id || ! $class_name) + return null; + + try { + return (Class_Album::class === $class_name) + ? ($class_name::find($id) ?? $class_name::findFirstBy(['id_origine' => $id])) + : $class_name::find($id); + } catch(Exception $e) { + return null; + } } } diff --git a/tests/application/modules/opac/controllers/AbonneControllerPaniersTest.php b/tests/application/modules/opac/controllers/AbonneControllerPaniersTest.php index 007beb22092dfb824593b79c248c7da5d667ad9e..6276de6101e8ed76d4bc7803b17ec097584f32e3 100644 --- a/tests/application/modules/opac/controllers/AbonneControllerPaniersTest.php +++ b/tests/application/modules/opac/controllers/AbonneControllerPaniersTest.php @@ -19,18 +19,21 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -class AbonneControllerPaniersForMarcusTest extends AbstractControllerTestCase { + +class AbonneControllerPaniersForMarcusTest extends AbstractControllerTestCase +{ + protected - $_storm_default_to_volatile = true, $marcus, $_xpath, $_json, $panier_bd; - public function setup() { + public function setup() + { parent::setup(); - $this->marcus = $this->fixture('Class_Users', + $this->marcus = $this->fixture(Class_Users::class, ['id' => 45, 'idabon' => 45, 'login' => 'marcus', @@ -38,7 +41,7 @@ class AbonneControllerPaniersForMarcusTest extends AbstractControllerTestCase { 'prenom' => 'marcus', 'nom' => 'bond']); - $marcel = $this->fixture('Class_Users', + $marcel = $this->fixture(Class_Users::class, ['id' => 47, 'login' => 'marcel', 'password' => 'secret', @@ -46,7 +49,7 @@ class AbonneControllerPaniersForMarcusTest extends AbstractControllerTestCase { 'nom' => 'doob']); $marcel->beAdminPortail()->assertSave(); - $coups_coeur_marcel = $this->fixture('Class_PanierNotice', + $coups_coeur_marcel = $this->fixture(Class_PanierNotice::class, ['id' => 4, 'id_panier' => 2, 'libelle' => 'Mes coups de coeur', @@ -54,16 +57,14 @@ class AbonneControllerPaniersForMarcusTest extends AbstractControllerTestCase { 'notices' => 'POMME API', 'user' => $marcel]); - $domaine_coups_coeur = $this->fixture('Class_Catalogue', + $domaine_coups_coeur = $this->fixture(Class_Catalogue::class, ['id' => 1, 'libelle' => 'Coups de coeur', 'panier_notices' => [$coups_coeur_marcel]]); - - ZendAfi_Auth::getInstance()->logUser($this->marcus); - $this->panier_bd = $this->fixture('Class_PanierNotice', + $this->panier_bd = $this->fixture(Class_PanierNotice::class, ['id' => 2, 'id_panier' => 1, 'libelle' => 'Mes BD', @@ -71,82 +72,196 @@ class AbonneControllerPaniersForMarcusTest extends AbstractControllerTestCase { 'notices' => 'COMBAT ORDINAIRE;BLACKSAD', 'user' => $this->marcus]); - - Storm_Test_ObjectWrapper::onLoaderOfModel('Class_PanierNotice') + Storm_Test_ObjectWrapper::onLoaderOfModel(Class_PanierNotice::class) ->whenCalled('findAllBy') ->answers([$this->panier_bd]); - Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Catalogue') + Storm_Test_ObjectWrapper::onLoaderOfModel(Class_Catalogue::class) ->whenCalled('findTopCatalogues') ->answers([$domaine_coups_coeur]); } /** @test **/ - public function getPaniersAsAdminShouldReturnMarcusPanierAsJSON() { + public function getPaniersAsAdminShouldReturnMarcusPanierAsJSON() + { $this->marcus->beModoBib(); - $this->dispatch('abonne/get-paniers.json',true); - - $this->assertJsonStringEqualsJsonString( - $this->_response->getBody(), - json_encode([ - ["id" => "panier_for_user", - "label" => "Mes paniers", - "categories" => [], - "items" => [ - ["id" => 2, - "label" => "Mes BD", - "options" => ["ico" => BASE_URL."/public/admin/images/picto/paniers_16.png"]]], - "options" => ["multipleSelection" => false]], - - [ - "id" => "domaines_paniers", - "label" => "Domaines", - "categories" => [ - ['id' => 1, - 'label' => 'Coups de coeur', - 'categories' => [], - 'items' => [ - ['id' => 4, - 'label' => 'Mes coups de coeur - marcel doob', - 'options' => [ - 'ico' => BASE_URL.'/public/admin/images/picto/paniers_16.png']] - ], - - 'options' => ['ico' => BASE_URL.'/public/admin/images/picto/domaines_16.png', - 'removeCheckbox' => true] - ] - ], - "items" => [], - "options" => ["ico" => BASE_URL."/public/admin/images/picto/domaines_16.png", - "multipleSelection" => false]]]), - $this->_response->getBody()); + $this->dispatch('abonne/get-paniers.json'); + + $this->assertJsonStringEqualsJsonString($this->_response->getBody(), + json_encode([ + ["id" => "panier_for_user", + "label" => "Mes paniers", + "categories" => [], + "items" => [ + ["id" => 2, + "label" => "Mes BD", + "options" => ["ico" => BASE_URL."/public/admin/images/picto/paniers_16.png"]]], + "options" => ["multipleSelection" => false]], + + [ + "id" => "domaines_paniers", + "label" => "Domaines", + "categories" => [ + ['id' => 1, + 'label' => 'Coups de coeur', + 'categories' => [], + 'items' => [ + ['id' => 4, + 'label' => 'Mes coups de coeur - marcel doob', + 'options' => [ + 'ico' => BASE_URL.'/public/admin/images/picto/paniers_16.png']] + ], + + 'options' => ['ico' => BASE_URL.'/public/admin/images/picto/domaines_16.png', + 'removeCheckbox' => true] + ] + ], + "items" => [], + "options" => ["ico" => BASE_URL."/public/admin/images/picto/domaines_16.png", + "multipleSelection" => false]]]), + $this->_response->getBody()); } /** @test **/ - public function getPaniersAsInviteShouldReturnMarcusPanierWithoutDomainesAsJSON() { + public function getPaniersAsInviteShouldReturnMarcusPanierWithoutDomainesAsJSON() + { $this->marcus->beInvite(); - $this->dispatch('abonne/get-paniers.json',true); - - $this->assertJsonStringEqualsJsonString( - $this->_response->getBody(), - json_encode([ - ["id" => "panier_for_user", - "label" => "Mes paniers", - "categories" => [], - "items" => [ - ["id" => 2, - "label" => "Mes BD", - "options" => ["ico" => BASE_URL."/public/admin/images/picto/paniers_16.png"]]], - "options" => ["multipleSelection" => false]] - ]), - $this->_response->getBody()); + $this->dispatch('abonne/get-paniers.json'); + + $this->assertJsonStringEqualsJsonString($this->_response->getBody(), + json_encode([ + ["id" => "panier_for_user", + "label" => "Mes paniers", + "categories" => [], + "items" => [ + ["id" => 2, + "label" => "Mes BD", + "options" => ["ico" => BASE_URL."/public/admin/images/picto/paniers_16.png"]]], + "options" => ["multipleSelection" => false]] + ]), + $this->_response->getBody()); + } +} + + + + +abstract class AbstractAbonneControllerPaniersDeleteTestCase extends AbstractControllerTestCase +{ + + public function setup() + { + parent::setup(); + + $marcel = $this->fixture(Class_Users::class, + ['id' => 47, + 'login' => 'marcel', + 'password' => 'secret', + 'prenom' => 'marcel', + 'nom' => 'doob']); + $marcel->beAdminPortail()->assertSave(); + + $cards = $this->fixture(Class_PanierNotice::class, + ['id' => 4, + 'id_panier' => 2, + 'libelle' => 'Mes coups de coeur', + 'date_maj' => '10/02/2011', + 'notices' => 'POMMEDAPI/Class_Album@1', + 'user' => $marcel]); + + $this->fixture(Class_Catalogue::class, + ['id' => 1, + 'libelle' => 'Coups de coeur', + 'panier_notices' => [$cards]]); + + $this->_fixtureAlbum(); + + $item = $this->fixture(Class_Exemplaire::class, + ['id' => 1, + 'notice_id' => 1, + 'id_origine' => 1]); + + $this->fixture(Class_Notice::class, + ['id' => 1, + 'type_doc' => 'ArteVod', + 'clef_alpha' => 'POMMEDAPI', + 'exemplaires' => [$item]]); + + ZendAfi_Auth::getInstance()->logUser($marcel); + + $this->dispatch('/abonne/supprimer-de-la-selection/id_profil/1/selection_id/4/record_id/1/delete/1'); + Class_PanierNotice::clearCache(); + } + + + protected function _fixtureAlbum() : self { + return $this; + } +} + + + + +class AbonneControllerPaniersDeleteWithExistsAlbumTest + extends AbstractAbonneControllerPaniersDeleteTestCase +{ + + protected function _fixtureAlbum() : self { + $this->fixture(Class_Album::class, + ['id' => 1, + 'titre' => 'Album title', + 'notice_id' => 1]); + + return $this; + } + + + /** @test */ + public function recordsKeysShouldHaveBeenErased() + { + $this->assertEquals([], Class_PanierNotice::find(4)->getClesNotices()); + } +} + + + + +class AbonneControllerPaniersDeleteWithExistsAlbumOnIdOrigineTest + extends AbstractAbonneControllerPaniersDeleteTestCase +{ + + protected function _fixtureAlbum() : self { + $this->fixture(Class_Album::class, + ['id' => 2, + 'titre' => 'Album title', + 'notice_id' => 1, + 'id_origine' => 1]); + + return $this; } + /** @test */ + public function recordsKeysShouldHaveBeenErased() + { + $this->assertEquals([], Class_PanierNotice::find(4)->getClesNotices()); + } } -?> \ No newline at end of file + + + +class AbonneControllerPaniersDeleteWithoutAlbumTest + extends AbstractAbonneControllerPaniersDeleteTestCase +{ + + /** @test */ + public function recordsKeysShouldHaveBeenErased() + { + $this->assertEquals([], Class_PanierNotice::find(4)->getClesNotices()); + } +}