diff --git a/library/Class/WebService/OAI/Request/ListIdentifiers.php b/library/Class/WebService/OAI/Request/ListIdentifiers.php index ade1c8387b3e64fe1958640320e3c92048672de5..261ad44cfafc945eda453fb58719bf7b26bf06ab 100644 --- a/library/Class/WebService/OAI/Request/ListIdentifiers.php +++ b/library/Class/WebService/OAI/Request/ListIdentifiers.php @@ -21,7 +21,7 @@ class Class_WebService_OAI_Request_ListIdentifiers { - const IDENTIFIERS_BY_PAGE = 100; + static int $identifiers_by_page = 100; protected @@ -122,16 +122,18 @@ class Class_WebService_OAI_Request_ListIdentifiers { if ( ! $this->_catalogue->hasRecords()) return $builder->error(['code' => 'noRecordsMatch']); - if (!$this->_token && static::IDENTIFIERS_BY_PAGE < $this->_total_count) - $this->_token = new Class_WebService_OAI_ResumptionToken($this->_params); + if ($this->_shouldDisplayResumptionToken()) + $this->_token = $this->_buildToken(); $page_number = $this->_token ? $this->_token->pageNumber() : 1; $this->_notices = Class_Catalogue::getNoticesByPreferences(['id_catalogue' => $this->_catalogue->getId(), - 'page' => $page_number, - 'page_size' => self::IDENTIFIERS_BY_PAGE]); + 'start_limit' => $page_number==1 + ? 0 + : ($page_number -1) *self::$identifiers_by_page + 1, + 'nb_notices' => self::$identifiers_by_page]); if (empty($this->_notices)) return $builder->error(['code' => 'noRecordsMatch']); } @@ -143,6 +145,25 @@ class Class_WebService_OAI_Request_ListIdentifiers { } + protected function _buildToken() : Class_WebService_OAI_ResumptionToken{ + return $this->_resumptionToken + ? Class_WebService_OAI_ResumptionToken::fromString($this->_resumptionToken) + : new Class_WebService_OAI_ResumptionToken($this->_params, + $this->_token + ? $this + ->_token + ->pageNumber() + : 1); + } + + + protected function _shouldDisplayResumptionToken(){ + return $this->_token + ? ($this->_token->pageNumber() * static::$identifiers_by_page) <= $this->_catalogue->getNoticesCount() + : static::$identifiers_by_page < $this->_catalogue->getNoticesCount(); + } + + public function getToken() { return $this->_token; } @@ -166,8 +187,10 @@ class Class_WebService_OAI_Request_ListIdentifiers { public function renderResumptionTokenOn($builder) { - return $this->_token - ? $this->_token->renderOn($builder, $this->_total_count) + return $this->_shouldDisplayResumptionToken() + ? $this->_token->renderOn($builder, $this->_total_count + ? $this->_total_count + : $this->_catalogue->getNoticesCount()) : ''; } diff --git a/library/Class/WebService/OAI/ResumptionToken.php b/library/Class/WebService/OAI/ResumptionToken.php index 5d521a95f90485fb08d4d9de9d3543840e976a20..8743388a9150e02b47cd168064afd5eb8844c548 100644 --- a/library/Class/WebService/OAI/ResumptionToken.php +++ b/library/Class/WebService/OAI/ResumptionToken.php @@ -23,9 +23,8 @@ class Class_WebService_OAI_ResumptionToken { const PARAM_SEPARATOR = '!'; - protected - $_params, - $_page_number = 1; + protected array $_params =[]; + protected int $_page_number = 1; public static function fromString($value) { @@ -74,12 +73,12 @@ class Class_WebService_OAI_ResumptionToken { public function renderOn($builder, $complete_list_size) { return $builder->resumptionToken(['completeListSize' => $complete_list_size, 'cursor' => $this->_cursor()], - $builder->cdata($this->__toString())); + $this->__toString()); } protected function _cursor() { - return ($this->_page_number-1) * 100; + return ($this->_page_number-1) * Class_WebService_OAI_Request_ListIdentifiers::$identifiers_by_page; } diff --git a/library/Class/WebService/OAIHarvester.php b/library/Class/WebService/OAIHarvester.php index 978d489cf464d372effe1a33892e808914adb7d9..035dbac795ddb29449f485c5d68caa04798144fb 100644 --- a/library/Class/WebService/OAIHarvester.php +++ b/library/Class/WebService/OAIHarvester.php @@ -25,7 +25,7 @@ class Class_WebService_OAIHarvester { const PAGE_SEPARATOR = "\n--BOKEH_OAI_PAGE-----------------\n", - RESUMPTION_PATTERN = '|<resumptionToken[^>]*>([^<]*)\</resumptionToken>|', + RESUMPTION_PATTERN = '|<resumptionToken[^>]*>(<!\[CDATA\[)?([^<\]]*)(\]\]>)?\<\/resumptionToken>|', ERROR_PATTERN = '|<error code="([a-zA-Z]+)"[^>]*>|', DATE_PATTERN = '|^[0-9]{4}-[0-9]{2}-[0-9]{2}$|', IDENTIFIER_PATTERN = '|<identifier[^>]*>[^<]*</identifier>|', @@ -138,7 +138,7 @@ class Class_WebService_OAIHarvester { protected function _parseToken($body) { return preg_match(static::RESUMPTION_PATTERN, $body, $matches) - ? $matches[1] + ? $matches[2] : null; } diff --git a/tests/application/modules/opac/controllers/OAIControllerListIdentifiersTest.php b/tests/application/modules/opac/controllers/OAIControllerListIdentifiersTest.php index e23b652caf05a775716550a7c698805d4f864aae..9f74b310c23edf2a35707ce5fc6080448939beb3 100644 --- a/tests/application/modules/opac/controllers/OAIControllerListIdentifiersTest.php +++ b/tests/application/modules/opac/controllers/OAIControllerListIdentifiersTest.php @@ -25,7 +25,8 @@ abstract class OAIControllerListIdentifiersTestCase protected $_xpath, $_xml, - $_catalog_loader; + $_catalog_loader, + $_sql; public function setUp() { @@ -65,10 +66,22 @@ abstract class OAIControllerListIdentifiersTestCase 'created_at' => '2012-04-03', 'date_maj' => '2017-10-09 11:42:42']); - Zend_Registry::set('sql', $this->mock()->beStrict() + $this->_sql = $this->mock()->beStrict() ->whenCalled('fetchAllByColumn') - ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,5000') - ->answers([2, 3, 4])); + ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,100') + ->answers([2, 3, 4]); + + $this->_adaptMockSql(); + + Zend_Registry::set('sql', $this->_sql); + } + + + protected function _adaptMockSql(){ + $this->_sql + ->whenCalled('fetchOne') + ->with('select count(*) from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1') + ->answers(3); } } @@ -186,23 +199,74 @@ class OAIControllerListIdentifiersValidTest class OAIControllerListIdentifiersWithPaginatorTest extends OAIControllerListIdentifiersTestCase { + public function setUp() { + parent::setUp(); + Class_WebService_OAI_Request_ListIdentifiers::$identifiers_by_page = 3; + $this->fixture(Class_Notice::class, + ['id' => 1, + 'type_doc' => 1, + 'clef_alpha' => 'STARWARS1', + 'created_at' => '2001-12-14', + 'date_maj' => '2017-10-09 11:42:42', + 'titre_principal' => 'Star Wars']); + for($i=5; $i<=8; $i++) + $this->fixture(Class_Notice::class, + ['id' => $i, + 'type_doc' => 1, + 'clef_alpha' => 'STARWARS'.$i, + 'created_at' => '2001-12-14', + 'date_maj' => '2017-10-09 11:42:42', + 'titre_principal' => 'Star Wars'.$i]); + } + + + public function tearDown(){ + Class_WebService_OAI_Request_ListIdentifiers::$identifiers_by_page = 100; + parent::tearDown(); + } + + + protected function _adaptMockSql(){ + $this->_sql + ->whenCalled('fetchOne') + ->with('select count(*) from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1') + ->answers(8) + ->whenCalled('fetchAllByColumn') + ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,3') + ->answers([1, 2, 3]) + ->whenCalled('fetchAllByColumn') + ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 4,3') + ->answers([4, 5, 6]) + ->whenCalled('fetchAllByColumn') + ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 7,3') + ->answers([7, 8]); + } + /** @test */ - public function firstPageShouldHaveResumptionTokenToPage2() { - $this->dispatch('/opac/oai/request?verb=ListIdentifiers&metadataPrefix=oai_dc&set=zork&resumptionToken=oai_dc!zork!!!1'); + public function pageCalledWithoutResumptionTokenShouldHaveResumptionTokenToPage2() { + $this->dispatch('/opac/oai/request?verb=ListIdentifiers&metadataPrefix=oai_dc&set=zork'); $this->_xpath->assertXPathContentContains($this->_response->getBody(), - '//oai:resumptionToken', + '//oai:resumptionToken[@completeListSize="8"][@cursor="0"]', 'oai_dc!zork!!!2'); } /** @test */ - public function secondPageShouldHaveResumptionTokenToPage3() { + public function pageCalledWithResumptionToken2ShouldHaveResumptionTokenToPage3() { $this->dispatch('/opac/oai/request?verb=ListIdentifiers&resumptionToken=oai_dc!zork!!!2'); $this->_xpath->assertXPathContentContains($this->_response->getBody(), - '//oai:resumptionToken', + '//oai:resumptionToken[@completeListSize="8"][@cursor="3"]', 'oai_dc!zork!!!3'); } + + + /** @test */ + public function pageCalledWithResumptionToken3ShouldNotHaveResumptionToken() { + $this->dispatch('/opac/oai/request?verb=ListIdentifiers&resumptionToken=oai_dc!zork!!!3'); + $this->_xpath->assertNotXPath($this->_response->getBody(), + '//oai:resumptionToken'); + } } @@ -321,8 +385,11 @@ class OAIControllerListIdentifiersWithEmptySetTest Zend_Registry::get('sql') ->whenCalled('fetchAllByColumn') - ->with('select notices.id_notice from notices Where (created_at <= \'2012-01-01\' and MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,5000') - ->answers([]); + ->with('select notices.id_notice from notices Where (created_at <= \'2012-01-01\' and MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,100') + ->answers([]) + ->whenCalled('fetchOne') + ->with('select count(*) from notices Where (created_at <= \'2012-01-01\' and MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1') + ->answers(0); $this->dispatch('/opac/oai/request?verb=ListIdentifiers&metadataPrefix=oai_dc&until=2012-01-01&set=zork'); $this->_xml = $this->_response->getBody(); diff --git a/tests/application/modules/opac/controllers/OAIControllerListRecordsTest.php b/tests/application/modules/opac/controllers/OAIControllerListRecordsTest.php index b6ad977ccee75e7e4e300814a071c59d2e6a124f..41bff3d761b76a7816460d002668533798157ee3 100644 --- a/tests/application/modules/opac/controllers/OAIControllerListRecordsTest.php +++ b/tests/application/modules/opac/controllers/OAIControllerListRecordsTest.php @@ -66,8 +66,11 @@ abstract class OAIControllerListRecordsInZorkSetTestCase Zend_Registry::set('sql', $this->mock()->beStrict() ->whenCalled('fetchAllByColumn') - ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,5000') - ->answers([2,3,4])); + ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,100') + ->answers([2,3,4]) + ->whenCalled('fetchOne') + ->with('select count(*) from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1') + ->answers(3)); } } @@ -80,6 +83,7 @@ class OAIControllerListRecordsInZorkSetTest public function setUp() { parent::setUp(); + $this->dispatch('/opac/oai/request?verb=ListRecords&metadataPrefix=oai_dc&set=zork'); $this->_body = $this->_response->getBody(); } @@ -287,8 +291,14 @@ class OAIControllerListRecordsInOaiDcBokehFormatTest Zend_Registry::set('sql', $this->mock()->beStrict() ->whenCalled('fetchAllByColumn') - ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,5000') - ->answers([1])); + ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,100') + ->answers([1]) + ->whenCalled('fetchOne') + ->with('select count(*) from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1') + ->answers(1) + ->whenCalled('fetchOne') + ->with('select count(*) from notices Where (created_at <= \'2012-01-01\' and MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1') + ->answers(1)); $this->dispatch('/opac/oai/request?verb=ListRecords&metadataPrefix=oai_dc_bokeh&set=albums'); $this->_body = $this->_response->getBody(); @@ -427,8 +437,11 @@ abstract class OAIControllerListRecordsIdentityProviderTest Zend_Registry::set('sql', $this->mock()->beStrict() ->whenCalled('fetchAllByColumn') - ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,5000') - ->answers([1])); + ->with('select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1 order by alpha_titre LIMIT 0,100') + ->answers([1]) + ->whenCalled('fetchOne') + ->with('select count(*) from notices Where (MATCH(facettes) AGAINST(\'+T1\' IN BOOLEAN MODE)) and type=1') + ->answers(1)); } } diff --git a/tests/scenarios/Numel/hcc_oai_2.xml b/tests/scenarios/Numel/hcc_oai_2.xml index c03b76746485e7d9c15a19bc2d9abe8e7f067505..88eea2d386151ce1ed609aa008f76aa2e331c1bd 100644 --- a/tests/scenarios/Numel/hcc_oai_2.xml +++ b/tests/scenarios/Numel/hcc_oai_2.xml @@ -2,6 +2,6 @@ <responseDate>2022-05-25T09:36:52Z</responseDate> <request verb="ListRecords">bd.correze.fr/oaiserver.ashx</request> <ListRecords> -<resumptionToken completeListSize="338426" cursor="338300">!!!338300!338426!oai_dc</resumptionToken> +<resumptionToken completeListSize="338426" cursor="338300"><![CDATA[!!!338300!338426!oai_dc]]></resumptionToken> </ListRecords> </OAI-PMH>