├── spec
├── data
│ ├── zero_loans_response.json
│ ├── item_no_loan_response.json
│ ├── zero_fees_response.json
│ ├── error_response.json
│ ├── analytics_still_loading_response.xml
│ ├── analytics_response_part4.xml
│ ├── error_response.xml
│ ├── per_second_threshold_error_response.json
│ ├── item_barcode_error_response.json
│ ├── report_not_found_response.xml
│ ├── file_response.json
│ ├── library_response.json
│ ├── users_response.json
│ ├── fee_response.json
│ ├── e-collections_response.json
│ ├── job_response.json
│ ├── fees_response.json
│ ├── create_loan_response.json
│ ├── jobs_response.json
│ ├── item_requests_response.json
│ ├── jobinstance_response.json
│ ├── portfolios_response.json
│ ├── item_loan_response.json
│ ├── representation_response.json
│ ├── jobinstances_response.json
│ ├── holdings_response.json
│ ├── e-collection_response.json
│ ├── representations_response.json
│ ├── holding_response.json
│ ├── holding_response.xml
│ ├── portfolio_response.json
│ ├── loans_response.json
│ ├── requested-resources_response.json
│ ├── bib_response_nz.xml
│ ├── item_response.json
│ ├── scanin_transit_response.json
│ └── bib_response_iz.xml
├── TaskLists
│ ├── ResourceSharingRequestSpec.php
│ ├── RequestedResourceSpec.php
│ ├── LendingRequestsSpec.php
│ └── RequestedResourcesSpec.php
├── Users
│ ├── RequestSpec.php
│ ├── FeeSpec.php
│ ├── LoanSpec.php
│ ├── RequestsSpec.php
│ ├── LoansSpec.php
│ ├── FeesSpec.php
│ ├── UsersSpec.php
│ └── UserSpec.php
├── Conf
│ ├── LibrarySpec.php
│ ├── LocationSpec.php
│ ├── JobInstanceSpec.php
│ ├── JobSpec.php
│ ├── JobsSpec.php
│ ├── LocationsSpec.php
│ ├── JobInstancesSpec.php
│ └── LibrariesSpec.php
├── Bibs
│ ├── FileSpec.php
│ ├── PortfoliosSpec.php
│ ├── RepresentationsSpec.php
│ ├── FilesSpec.php
│ ├── ElectronicCollectionsSpec.php
│ ├── PortfolioSpec.php
│ ├── RepresentationSpec.php
│ ├── HoldingSpec.php
│ ├── ItemsSpec.php
│ ├── HoldingsSpec.php
│ ├── BibSpec.php
│ ├── BibsSpec.php
│ └── ItemSpec.php
├── Analytics
│ ├── AnalyticsSpec.php
│ ├── RowSpec.php
│ └── ReportSpec.php
├── Electronic
│ └── CollectionSpec.php
└── SpecHelper.php
├── .gitignore
├── .styleci.yml
├── phpspec-ci.yml
├── src
├── Exception
│ ├── InvalidQuery.php
│ ├── InvalidApiKey.php
│ ├── ResourceNotFound.php
│ ├── SruClientNotSetException.php
│ ├── MaxNumberOfAttemptsExhausted.php
│ ├── ClientException.php
│ ├── NoLinkedNetworkZoneRecordException.php
│ └── RequestFailed.php
├── Zones.php
├── Conf
│ ├── Conf.php
│ ├── Location.php
│ ├── JobInstance.php
│ ├── Library.php
│ ├── Jobs.php
│ ├── Job.php
│ ├── Libraries.php
│ ├── JobInstances.php
│ └── Locations.php
├── Laravel
│ ├── Facade.php
│ └── ServiceProvider.php
├── TaskLists
│ ├── ResourceSharingRequest.php
│ ├── TaskLists.php
│ ├── RequestedResource.php
│ ├── RequestedResources.php
│ └── LendingRequests.php
├── Analytics
│ ├── Analytics.php
│ └── Row.php
├── Model
│ ├── ReadOnlyArrayAccess.php
│ ├── IterableCollection.php
│ ├── PaginatedListGenerator.php
│ ├── PaginatedList.php
│ ├── SimplePaginatedList.php
│ ├── LazyResourceList.php
│ ├── Model.php
│ └── LazyResource.php
├── Users
│ ├── Request.php
│ ├── Loans.php
│ ├── Requests.php
│ ├── Fee.php
│ ├── Loan.php
│ ├── Fees.php
│ ├── UserIdentifiers.php
│ └── Users.php
├── Electronic
│ └── Collection.php
└── Bibs
│ ├── Portfolio.php
│ ├── Representation.php
│ ├── File.php
│ ├── Portfolios.php
│ ├── Representations.php
│ ├── ElectronicCollections.php
│ ├── Holdings.php
│ ├── Files.php
│ ├── ScanInResponse.php
│ ├── Holding.php
│ ├── Items.php
│ ├── Bibs.php
│ └── Item.php
├── .scrutinizer.yml
├── .sonarcloud.properties
├── phpspec.yml
├── .travis.yml
├── ruleset.xml
├── phpunit.xml
├── .circleci
└── config.yml
├── LICENSE
├── .overcommit.yml
├── config
└── alma.php
└── composer.json
/spec/data/zero_loans_response.json:
--------------------------------------------------------------------------------
1 | {"total_record_count":0}
--------------------------------------------------------------------------------
/spec/data/item_no_loan_response.json:
--------------------------------------------------------------------------------
1 | {"total_record_count":0}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | /build/
3 | composer.lock
4 | coverage.xml
5 | coverage
6 |
--------------------------------------------------------------------------------
/spec/data/zero_fees_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "total_record_count": 0,
3 | "total_sum": 0,
4 | "currency": null
5 | }
6 |
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: recommended
2 |
3 | disabled:
4 | - concat_without_spaces
5 |
6 | enabled:
7 | - concat_with_spaces
8 |
--------------------------------------------------------------------------------
/phpspec-ci.yml:
--------------------------------------------------------------------------------
1 | suites:
2 | alma_suite:
3 | namespace: Scriptotek\Alma
4 | psr4_prefix: Scriptotek\Alma
5 | formatter.name: pretty
6 |
--------------------------------------------------------------------------------
/src/Exception/InvalidQuery.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | build:
2 | tests:
3 | override:
4 | -
5 | command: 'vendor/bin/phpspec run -f progress -c phpspec-ci.yml'
6 | # coverage:
7 | # file: 'coverage.clover'
8 | # format: 'php-clover'
9 |
--------------------------------------------------------------------------------
/.sonarcloud.properties:
--------------------------------------------------------------------------------
1 | # Path to sources
2 | #sonar.sources=.
3 | #sonar.exclusions=
4 | #sonar.inclusions=
5 |
6 | # Path to tests
7 | #sonar.tests=
8 | #sonar.test.exclusions=
9 | #sonar.test.inclusions=
10 |
11 | # Source encoding
12 | #sonar.sourceEncoding=UTF-8
13 |
14 | # Exclusions for copy-paste detection
15 | #sonar.cpd.exclusions=
16 |
--------------------------------------------------------------------------------
/phpspec.yml:
--------------------------------------------------------------------------------
1 | suites:
2 | alma_suite:
3 | namespace: Scriptotek\Alma
4 | psr4_prefix: Scriptotek\Alma
5 | formatter.name: pretty
6 | # extensions:
7 | # PhpSpecCodeCoverage\CodeCoverageExtension:
8 | # format:
9 | # - html
10 | # - clover
11 | # output:
12 | # html: coverage
13 | # clover: coverage.xml
14 |
--------------------------------------------------------------------------------
/src/Conf/Conf.php:
--------------------------------------------------------------------------------
1 | client = $client;
12 | $this->libraries = new Libraries($client);
13 | $this->jobs = new Jobs($client);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 | dist: bionic
3 |
4 | php:
5 | - 7.2
6 | - 7.3
7 | - 7.4
8 |
9 | before_script:
10 | - echo 'date.timezone = "UTC"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
11 | - composer install --no-interaction --optimize-autoloader
12 |
13 | script:
14 | - vendor/bin/phpspec run --verbose --no-interaction
15 |
--------------------------------------------------------------------------------
/spec/data/analytics_response_part4.xml:
--------------------------------------------------------------------------------
1 | true420033No more rows to fetchE01-2308152114-DU9TC-AWAE716956513
--------------------------------------------------------------------------------
/spec/data/error_response.xml:
--------------------------------------------------------------------------------
1 | true401664Mandatory field is missing: libraryE02-2807130150-8OWYS-AWAE533535741
--------------------------------------------------------------------------------
/spec/data/per_second_threshold_error_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "errorList": {
3 | "error": [
4 | {
5 | "errorCode": "PER_SECOND_THRESHOLD",
6 | "errorMessage": "HTTP requests are more than allowed per second. See https://goo.gl/2x1c1M "
7 | }
8 | ]
9 | },
10 | "errorsExist": true,
11 | "result": null
12 | }
--------------------------------------------------------------------------------
/spec/data/item_barcode_error_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "errorList": {
3 | "error": [
4 | {
5 | "errorCode": "401689",
6 | "errorMessage": "No items found for barcode 123.",
7 | "trackingId": "E02-2307205340-QCHPA-AWAE1768653911"
8 | }
9 | ]
10 | },
11 | "errorsExist": true,
12 | "result": null
13 | }
--------------------------------------------------------------------------------
/spec/data/report_not_found_response.xml:
--------------------------------------------------------------------------------
1 | trueINTERNAL_SERVER_ERRORPath not found (/test/path)E01-2907105336-JL6QZ-AWAE1528523551
--------------------------------------------------------------------------------
/spec/data/file_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "pid": "13216677500002204",
3 | "path": "47BIBSYS_UBO/storage/alma/36/3A/65/88/BA/6D/E0/92/B2/57/23/07/75/65/57/4E/75nb26737_side085.tif",
4 | "thumbnail_url": "https://eu01.alma.exlibrisgroup.com/view/delivery/thumbnail/47BIBSYS_UBO/13216677500002204",
5 | "label": "75nb26737_side085",
6 | "size": 16086776,
7 | "url": null,
8 | "fulltext": null
9 | }
10 |
--------------------------------------------------------------------------------
/spec/TaskLists/ResourceSharingRequestSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $id);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | PSR2 without namespace requirement.
4 |
5 |
6 | */database/*
7 |
8 |
9 | */tests/*
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/Laravel/Facade.php:
--------------------------------------------------------------------------------
1 | request_id = $id;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 | src
10 |
11 |
12 |
13 |
14 |
15 | tests/
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/spec/data/library_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "campus": {
3 | "desc": "UiO Blindern",
4 | "value": "BLINDERN"
5 | },
6 | "code": "1030310",
7 | "default_location": {
8 | "desc": "UREAL Boksamling",
9 | "value": "k00423"
10 | },
11 | "description": "UiO Realfagsbiblioteket",
12 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/conf/libraries/1030310",
13 | "name": "UiO Realfagsbiblioteket",
14 | "path": "47BIBSYS.47BIBSYS_UBO.1030310",
15 | "proxy": "",
16 | "resource_sharing": true
17 | }
--------------------------------------------------------------------------------
/spec/Users/RequestSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $user, '123');
15 | }
16 |
17 | public function it_is_initializable()
18 | {
19 | $this->shouldHaveType(Request::class);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Analytics/Analytics.php:
--------------------------------------------------------------------------------
1 | client = $client;
21 | }
22 |
23 | public function get(...$args)
24 | {
25 | return new Report($this->client, ...$args);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Model/ReadOnlyArrayAccess.php:
--------------------------------------------------------------------------------
1 | get($offset)->exists();
20 | }
21 |
22 | public function offsetGet($offset): mixed
23 | {
24 | return $this->get($offset);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # PHP CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-php/ for more details
4 | #
5 | ---
6 | version: 2
7 | jobs:
8 | build:
9 | docker:
10 | # Reference: https://circleci.com/docs/2.0/circleci-images/
11 | - image: circleci/php:7.2-node-browsers
12 |
13 | working_directory: ~/repo
14 |
15 | steps:
16 | - checkout
17 |
18 | # Download dependencies
19 | # (no caching at this point since we use some in dev state)
20 | - run: composer install -n --prefer-dist
21 |
22 | # run tests!
23 | - run: vendor/bin/phpspec run --verbose --no-interaction
24 |
--------------------------------------------------------------------------------
/spec/TaskLists/RequestedResourceSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $library, 'SUPER_DESK', $bib);
16 | }
17 |
18 | public function it_is_initializable()
19 | {
20 | $this->shouldHaveType(RequestedResource::class);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/spec/data/users_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "total_record_count": 1,
3 | "user": [
4 | {
5 | "fees": null,
6 | "first_name": "Dan",
7 | "gender": {
8 | "desc": "",
9 | "value": ""
10 | },
11 | "last_name": "Banan",
12 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/users/1234567",
13 | "loans": null,
14 | "password": "",
15 | "primary_id": "1234567",
16 | "requests": null,
17 | "status": {
18 | "desc": "Active",
19 | "value": "ACTIVE"
20 | }
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/src/Model/IterableCollection.php:
--------------------------------------------------------------------------------
1 | init()->resources[$this->position];
12 | }
13 |
14 | public function key(): int
15 | {
16 | return $this->position;
17 | }
18 |
19 | public function next(): void
20 | {
21 | $this->position++;
22 | }
23 |
24 | public function rewind(): void
25 | {
26 | $this->position = 0;
27 | }
28 |
29 | public function valid(): bool
30 | {
31 | return $this->position < $this->count();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/spec/Conf/LibrarySpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $libraryCode);
16 | }
17 |
18 | public function it_is_initializable()
19 | {
20 | $this->shouldHaveType(Library::class);
21 | }
22 |
23 | public function it_should_have_locations()
24 | {
25 | $this->locations->shouldBeAnInstanceOf(Locations::class);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/spec/data/fee_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "9854064491211104",
3 | "type": {
4 | "value": "LOSTITEMREPLACEMENTFEE",
5 | "desc": "Lost item replacement fee"
6 | },
7 | "status": {
8 | "value": "ACTIVE",
9 | "desc": "Active"
10 | },
11 | "balance": 750,
12 | "remaining_vat_amount": 0,
13 | "original_amount": 750,
14 | "original_vat_amount": 0,
15 | "creation_time": "2018-01-05T04:49:27.349Z",
16 | "status_time": "2018-01-05T04:49:27.349Z",
17 | "comment": null,
18 | "owner": {
19 | "value": "1030310",
20 | "desc": "UiO Realfagsbiblioteket"
21 | },
22 | "title": "Knowledge concepts",
23 | "barcode": null,
24 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/users/12345/fees/9854064491211104"
25 | }
26 |
--------------------------------------------------------------------------------
/spec/Conf/LocationSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $library, $location_code);
16 | }
17 |
18 | public function it_is_initializable()
19 | {
20 | $this->shouldHaveType(Location::class);
21 | }
22 |
23 | public function it_should_belong_to_a_library()
24 | {
25 | $this->library->shouldBeAnInstanceOf(Library::class);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/spec/Conf/JobInstanceSpec.php:
--------------------------------------------------------------------------------
1 | job_id = '123';
15 | $instanceId = '1108569450000121';
16 | $this->beConstructedWith($client, $job, $instanceId);
17 | }
18 |
19 | public function it_is_initializable()
20 | {
21 | $this->shouldHaveType(JobInstance::class);
22 | }
23 |
24 | public function it_should_belong_to_a_job()
25 | {
26 | $this->job->shouldBeAnInstanceOf(Job::class);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/spec/Bibs/FileSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = '990006312214702204';
16 | $representation->representation_id = '22163771200002204';
17 | $file_id = '23163771190002204';
18 |
19 | $this->beConstructedWith($client, $bib, $representation, $file_id);
20 | }
21 |
22 | public function it_is_initializable()
23 | {
24 | $this->shouldHaveType(File::class);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/spec/Conf/JobSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, 'M26714670000011');
15 |
16 | $client->getJSON('/conf/jobs/M26714670000011')
17 | ->willReturn(SpecHelper::getDummyData('job_response.json'));
18 | $client->postJSON('/conf/jobs/M26714670000011?op=run')
19 | ->willReturn(SpecHelper::getDummyData('job_response.json'));
20 | }
21 |
22 | public function it_is_initializable()
23 | {
24 | $this->shouldHaveType(Job::class);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/spec/data/e-collections_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "electronic_collection": [
3 | {
4 | "id": "61173723710002204",
5 | "is_local": false,
6 | "public_name": "SpringerLink Books Complete",
7 | "description": "",
8 | "library": null,
9 | "type": {
10 | "value": "0",
11 | "desc": "Selective package"
12 | },
13 | "license": null,
14 | "source": null,
15 | "creator": null,
16 | "url": null,
17 | "free": null,
18 | "proxy": null,
19 | "language": null,
20 | "category": null,
21 | "portfolios": {
22 | "value": 55900,
23 | "link": null
24 | },
25 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/electronic/e-collections/61173723710002204"
26 | }
27 | ],
28 | "total_record_count": 1
29 | }
30 |
--------------------------------------------------------------------------------
/src/TaskLists/TaskLists.php:
--------------------------------------------------------------------------------
1 | client = $client;
20 | }
21 |
22 | public function getLendingRequests(Library $library, $params = [])
23 | {
24 | return new LendingRequests($this->client, $library, $params);
25 | }
26 |
27 | public function getRequestedResources(Library $library, $circ_desk = 'DEFAULT_CIRC_DESK', $params = [])
28 | {
29 | return new RequestedResources($this->client, $library, $circ_desk, $params);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/TaskLists/RequestedResource.php:
--------------------------------------------------------------------------------
1 | library = $library;
28 | $this->circ_desk = $circ_desc;
29 | $this->bib = $bib;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/spec/Users/FeeSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $user, $fee_id);
17 | }
18 |
19 | public function it_is_initializable()
20 | {
21 | $this->shouldHaveType(Fee::class);
22 | }
23 |
24 | public function it_can_exist()
25 | {
26 | $this->init(SpecHelper::getDummyData('fee_response.json'));
27 |
28 | $this->exists()->shouldBe(true);
29 | $this->balance->shouldBe(750);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/spec/Analytics/AnalyticsSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($almaClient);
13 | }
14 |
15 | public function it_is_initializable()
16 | {
17 | $this->shouldHaveType('Scriptotek\Alma\Analytics\Analytics');
18 | }
19 |
20 | public function it_provides_an_interface_to_report_objects()
21 | {
22 | $path = 'UIO,Universitetsbiblioteket/Reports/RSS/Nyhetslister : Fransk'; // str_random();
23 |
24 | $report = $this->get($path);
25 |
26 | $report->shouldHaveType('Scriptotek\Alma\Analytics\Report');
27 | $report->path->shouldBe($path);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/spec/Electronic/CollectionSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $collection_id);
16 | }
17 |
18 | protected function expectRequest($client)
19 | {
20 | $client->getJSON('/electronic/e-collections/123')
21 | ->shouldBeCalled()
22 | ->willReturn(SpecHelper::getDummyData('e-collection_response.json'));
23 | }
24 |
25 | public function it_is_initializable()
26 | {
27 | $this->shouldHaveType(Collection::class);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/spec/data/job_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "link": "string",
3 | "id": "M26714670000011",
4 | "name": "Export Physical Items",
5 | "description": "Export Physical Items",
6 | "type": {
7 | "desc": "Manual",
8 | "value": "MANUAL"
9 | },
10 | "category": {
11 | "desc": "Normalization",
12 | "value": "NORMALIZATION"
13 | },
14 | "content": {
15 | "desc": "All Titles",
16 | "value": "BIB_MMS"
17 | },
18 | "schedule": {
19 | "desc": "Not scheduled",
20 | "value": "NOT_SCHEDULED"
21 | },
22 | "creator": "string",
23 | "next_run": "2024-05-30T09:30:10Z",
24 | "parameter": [
25 | {
26 | "name": {
27 | "desc": "string",
28 | "value": "string"
29 | },
30 | "value": "string"
31 | }
32 | ],
33 | "related_profile": {
34 | "link": "string",
35 | "value": "ID123"
36 | },
37 | "additional_info": {
38 | "link": "string",
39 | "value": "string"
40 | }
41 | }
--------------------------------------------------------------------------------
/spec/Users/LoanSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $user, $item, $loan_id);
18 | }
19 |
20 | public function it_is_initializable()
21 | {
22 | $this->shouldHaveType(Loan::class);
23 | }
24 |
25 | public function it_can_exist()
26 | {
27 | $this->init(SpecHelper::getDummyData('item_loan_response.json')->item_loan[0]);
28 |
29 | $this->exists()->shouldBe(true);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/spec/Users/RequestsSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $url);
16 | }
17 |
18 | public function it_is_countable(AlmaClient $client)
19 | {
20 | $client->getJSON('/bibs/1/holdings/2/items/3/requests')
21 | ->shouldBeCalled()
22 | ->willReturn(SpecHelper::getDummyData('item_requests_response.json'));
23 |
24 | $this->shouldHaveCount(1);
25 | }
26 |
27 | public function it_is_initializable()
28 | {
29 | $this->shouldHaveType(Requests::class);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/spec/data/fees_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "fee": [
3 | {
4 | "id": "9854064491211104",
5 | "type": {
6 | "value": "LOSTITEMREPLACEMENTFEE",
7 | "desc": "Lost item replacement fee"
8 | },
9 | "status": {
10 | "value": "ACTIVE",
11 | "desc": "Active"
12 | },
13 | "balance": 750,
14 | "remaining_vat_amount": 0,
15 | "original_amount": 750,
16 | "original_vat_amount": 0,
17 | "creation_time": "2018-01-05T04:49:27.349Z",
18 | "status_time": "2018-01-05T04:49:27.349Z",
19 | "comment": null,
20 | "owner": {
21 | "value": "1030310",
22 | "desc": "UiO Realfagsbiblioteket"
23 | },
24 | "title": "Knowledge concepts",
25 | "barcode": null,
26 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/users/12345/fees/9854064491211104"
27 | }
28 | ],
29 | "total_record_count": 1,
30 | "total_sum": 750,
31 | "currency": "NOK"
32 | }
33 |
--------------------------------------------------------------------------------
/src/Exception/RequestFailed.php:
--------------------------------------------------------------------------------
1 | errorCode = $errorCode;
24 |
25 | parent::__construct($message, 0, $previous);
26 | }
27 |
28 | /**
29 | * Returns the error code string.
30 | */
31 | public function getErrorCode()
32 | {
33 | return $this->errorCode;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/spec/data/create_loan_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Vollset, K.",
3 | "call_number": "Ung 839.82 Vol:Ban",
4 | "circ_desk": {
5 | "desc": "Utlånet Ureal",
6 | "value": "DEFAULT_CIRC_DESK"
7 | },
8 | "description": null,
9 | "due_date": "2018-08-10T18:00:00Z",
10 | "item_barcode": "303011kj0",
11 | "item_policy": {
12 | "description": null,
13 | "value": null
14 | },
15 | "library": {
16 | "desc": "UiO HumSam-biblioteket",
17 | "value": "1030300"
18 | },
19 | "loan_date": "2018-07-13T17:31:39.800Z",
20 | "loan_id": "7329587120002204",
21 | "loan_status": "ACTIVE",
22 | "location_code": {
23 | "name": "UHS S-Litt",
24 | "value": "k00040"
25 | },
26 | "mms_id": "990006312214702204",
27 | "process_status": "NORMAL",
28 | "publication_year": "2000",
29 | "renewable": true,
30 | "title": "Bananboken K. Vollset ; [illustrasjoner: Motorfinger og Jim]",
31 | "user_id": "Dan Michael"
32 | }
--------------------------------------------------------------------------------
/spec/data/jobs_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "total_record_count": 1,
3 | "job": [
4 | {
5 | "link": "string",
6 | "id": "M26714670000011",
7 | "name": "Export Physical Items",
8 | "description": "Export Physical Items",
9 | "type": {
10 | "desc": "Manual",
11 | "value": "MANUAL"
12 | },
13 | "category": {
14 | "desc": "Normalization",
15 | "value": "NORMALIZATION"
16 | },
17 | "content": {
18 | "desc": "All Titles",
19 | "value": "BIB_MMS"
20 | },
21 | "schedule": {
22 | "desc": "Not scheduled",
23 | "value": "NOT_SCHEDULED"
24 | },
25 | "creator": "string",
26 | "next_run": "2024-05-30T09:30:10Z",
27 | "parameter": [
28 | {
29 | "name": {
30 | "desc": "string",
31 | "value": "string"
32 | },
33 | "value": "string"
34 | }
35 | ],
36 | "related_profile": {
37 | "link": "string",
38 | "value": "ID123"
39 | },
40 | "additional_info": {
41 | "link": "string",
42 | "value": "string"
43 | }
44 | }
45 | ]
46 | }
--------------------------------------------------------------------------------
/spec/Bibs/PortfoliosSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = 'abc';
16 | $this->beConstructedWith($client, $bib);
17 | }
18 |
19 | public function it_is_initializable()
20 | {
21 | $this->shouldHaveType(Portfolios::class);
22 | }
23 |
24 | protected function expectRequest($client)
25 | {
26 | $client->getJSON('/bibs/abc/portfolios')
27 | ->shouldBeCalled()
28 | ->willReturn(SpecHelper::getDummyData('portfolios_response.json'));
29 | }
30 |
31 | public function it_is_countable(AlmaClient $client)
32 | {
33 | $this->expectRequest($client);
34 |
35 | $this->shouldHaveCount(1);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/spec/Bibs/RepresentationsSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = 'abc';
16 | $this->beConstructedWith($client, $bib);
17 | }
18 |
19 | public function it_is_initializable()
20 | {
21 | $this->shouldHaveType(Representations::class);
22 | }
23 |
24 | protected function expectRequest($client)
25 | {
26 | $client->getJSON('/bibs/abc/representations')
27 | ->shouldBeCalled()
28 | ->willReturn(SpecHelper::getDummyData('representations_response.json'));
29 | }
30 |
31 | public function it_is_countable(AlmaClient $client)
32 | {
33 | $this->expectRequest($client);
34 |
35 | $this->shouldHaveCount(2);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/spec/TaskLists/LendingRequestsSpec.php:
--------------------------------------------------------------------------------
1 | code = 'SOME_LIBRARY';
16 | $this->beConstructedWith($client, $library, [
17 | 'printed' => 'N',
18 | 'status' => 'REQUEST_CREATED_LEND',
19 | ]);
20 |
21 | $client->getJSON('/task-lists/rs/lending-requests?printed=N&status=REQUEST_CREATED_LEND&library=SOME_LIBRARY')
22 | ->shouldBeCalledTimes(1)
23 | ->willReturn(SpecHelper::getDummyData('lending_requests_created.json'));
24 |
25 | $this->all()->shouldBeArray();
26 | $this->all()->shouldHaveCount(3);
27 | $this->all()[0]->shouldBeAnInstanceOf(ResourceSharingRequest::class);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Conf/Location.php:
--------------------------------------------------------------------------------
1 | library = $library;
23 | $this->code = $code;
24 | }
25 |
26 | /**
27 | * Check if we have the full representation of our data object.
28 | *
29 | * @param \stdClass $data
30 | *
31 | * @return bool
32 | */
33 | protected function isInitialized($data)
34 | {
35 | return isset($data->location);
36 | }
37 |
38 | /**
39 | * Generate the base URL for this resource.
40 | *
41 | * @return string
42 | */
43 | protected function urlBase()
44 | {
45 | return "/conf/libraries/{$this->library->code}/locations/{$this->code}";
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Dan Michael O. Heggø
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/spec/Conf/JobsSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client);
16 | }
17 |
18 | public function it_provides_a_lazy_interface_to_job_objects(AlmaClient $client)
19 | {
20 | SpecHelper::expectNoRequests($client);
21 |
22 | $job_id = 'M26714670000011';
23 | $job = $this->get($job_id);
24 |
25 | $job->shouldBeAnInstanceOf(Job::class);
26 | $job->job_id->shouldBe($job_id);
27 | }
28 |
29 | public function it_provides_jobs(AlmaClient $client)
30 | {
31 | $client->getJSON(Argument::containingString('/conf/jobs?'))
32 | ->shouldBeCalled()
33 | ->willReturn(SpecHelper::getDummyData('jobs_response.json'));
34 |
35 | $this->all()->shouldBeArray();
36 | $this->all()[0]->shouldBeAnInstanceOf(Job::class);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Users/Request.php:
--------------------------------------------------------------------------------
1 | user = $user;
23 | $this->request_id = $request_id;
24 | }
25 |
26 | /**
27 | * Check if we have the full representation of our data object.
28 | *
29 | * @param \stdClass $data
30 | *
31 | * @return bool
32 | */
33 | protected function isInitialized($data)
34 | {
35 | return isset($data->request_type);
36 | }
37 |
38 | /**
39 | * Generate the base URL for this resource.
40 | *
41 | * @return string
42 | */
43 | protected function urlBase()
44 | {
45 | return sprintf('/users/%s/requests/%s', rawurlencode($this->user->id), $this->request_id);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/spec/data/item_requests_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "total_record_count": 1,
3 | "user_request": [
4 | {
5 | "author": "Osipov, Andrey V.",
6 | "barcode": null,
7 | "comment": null,
8 | "description": null,
9 | "material_type": {
10 | "desc": null,
11 | "value": null
12 | },
13 | "mms_id": "999919897211902204",
14 | "pickup_location": "UiO Realfagsbiblioteket",
15 | "pickup_location_library": "1030310",
16 | "pickup_location_type": "LIBRARY",
17 | "place_in_queue": 1,
18 | "request_date": "2018-07-31Z",
19 | "request_id": "1403795240001204",
20 | "request_status": "NOT_STARTED",
21 | "request_sub_type": {
22 | "desc": "Patron physical item request",
23 | "value": "PATRON_PHYSICAL"
24 | },
25 | "request_type": "HOLD",
26 | "title": "Modern electromagnetic scattering theory with applications Andrey V. Osipov, Sergei A. Tretyakov",
27 | "user_primary_id": "Some User"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/spec/Bibs/FilesSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = 'abc';
17 | $representation->representation_id = '123';
18 | $this->beConstructedWith($client, $bib, $representation);
19 | }
20 |
21 | public function it_is_initializable()
22 | {
23 | $this->shouldHaveType(Files::class);
24 | }
25 |
26 | protected function expectRequest($client)
27 | {
28 | $client->getJSON('/bibs/abc/representations/123/files')
29 | ->shouldBeCalled()
30 | ->willReturn(SpecHelper::getDummyData('files_response.json'));
31 | }
32 |
33 | public function it_is_countable(AlmaClient $client)
34 | {
35 | $this->expectRequest($client);
36 |
37 | $this->shouldHaveCount(96);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/spec/data/jobinstance_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "link": "string",
3 | "id": "1108569450000121",
4 | "external_id": "1108569450000121",
5 | "name": "Export Physical Items - war and love - 04/15/2015 16:07",
6 | "submitted_by": {
7 | "desc": "string",
8 | "value": "exl_impl"
9 | },
10 | "submit_time": "2015-04-15T13:07:40.800Z",
11 | "start_time": "2015-04-15T13:07:40.868Z",
12 | "end_time": "2015-04-15T13:07:44.359Z",
13 | "progress": 100,
14 | "status": {
15 | "desc": "string",
16 | "value": "QUEUED"
17 | },
18 | "status_date": "2015-07-20",
19 | "alert": [
20 | {
21 | "desc": "string",
22 | "value": "alert_general_success"
23 | }
24 | ],
25 | "counter": [
26 | {
27 | "type": {
28 | "desc": "string",
29 | "value": "4"
30 | },
31 | "value": "string"
32 | }
33 | ],
34 | "action": [
35 | "string"
36 | ],
37 | "job_info": {
38 | "link": "string",
39 | "id": "1108569450000121",
40 | "name": "Export Physical Items - war and love - 04/15/2015 16:07",
41 | "description": "string",
42 | "type": {
43 | "desc": "string",
44 | "value": "CREATE_SET"
45 | },
46 | "category": {
47 | "desc": "string",
48 | "value": "NORMALIZATION"
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/.overcommit.yml:
--------------------------------------------------------------------------------
1 | # Use this file to configure the Overcommit hooks you wish to use. This will
2 | # extend the default configuration defined in:
3 | # https://github.com/brigade/overcommit/blob/master/config/default.yml
4 | #
5 | # At the topmost level of this YAML file is a key representing type of hook
6 | # being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
7 | # customize each hook, such as whether to only run it on certain files (via
8 | # `include`), whether to only display output if it fails (via `quiet`), etc.
9 | #
10 | # For a complete list of hooks, see:
11 | # https://github.com/brigade/overcommit/tree/master/lib/overcommit/hook
12 | #
13 | # For a complete list of options that you can use to customize hooks, see:
14 | # https://github.com/brigade/overcommit#configuration
15 | #
16 | # Uncomment the following lines to make the configuration take effect.
17 | ---
18 | PreCommit:
19 | TrailingWhitespace:
20 | enabled: true
21 | problem_on_unmodified_line: warn
22 | PhpCs:
23 | enabled: true
24 | command: 'vendor/bin/phpcs'
25 | flags: ['--standard=ruleset.xml', '--report=csv', '-s']
26 | problem_on_unmodified_line: warn
27 | exclude:
28 | - 'spec/**/*'
29 | PhpLint:
30 | enabled: true
31 | on_warn: fail
32 |
33 |
--------------------------------------------------------------------------------
/spec/Conf/LocationsSpec.php:
--------------------------------------------------------------------------------
1 | code = 'LIB_CODE';
16 | $this->beConstructedWith($client, $library);
17 | }
18 |
19 | public function it_provides_a_lazy_interface_to_location_objects(AlmaClient $client)
20 | {
21 | SpecHelper::expectNoRequests($client);
22 |
23 | $code = 'LOC_CODE';
24 | $location = $this->get($code);
25 |
26 | $location->shouldBeAnInstanceOf(Location::class);
27 | $location->code->shouldBe($code);
28 | }
29 |
30 | public function it_provides_locations(AlmaClient $client)
31 | {
32 | $client->getJSON('/conf/libraries/LIB_CODE/locations')
33 | ->shouldBeCalled()
34 | ->willReturn(SpecHelper::getDummyData('locations_response.json'));
35 |
36 | $this->all()->shouldBeArray();
37 | $this->all()[0]->shouldBeAnInstanceOf(Location::class);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/spec/data/portfolios_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "portfolio": [
3 | {
4 | "id": "53182555270002204",
5 | "is_local": false,
6 | "is_standalone": false,
7 | "resource_metadata": {
8 | "mms_id": {
9 | "value": "999919790879802204",
10 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999919790879802204"
11 | },
12 | "title": "Elementary Mechanics Using Matlab A Modern Course Combining Analytical and Numerical Techniques /"
13 | },
14 | "electronic_collection": {
15 | "id": {
16 | "value": "61173723710002204",
17 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/electronic/e-collections/61173723710002204"
18 | },
19 | "service": {
20 | "value": "62173726760002204",
21 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/electronic/e-collections/61173723710002204/e-services/62173726760002204"
22 | }
23 | },
24 | "availability": {
25 | "value": "11",
26 | "desc": "Available"
27 | },
28 | "library": null,
29 | "license": null,
30 | "pda": null,
31 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999919790879802204/portfolios/53182555270002204"
32 | }
33 | ],
34 | "total_record_count": 1
35 | }
36 |
--------------------------------------------------------------------------------
/spec/data/item_loan_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "item_loan": [
3 | {
4 | "author": "Vollset, K.",
5 | "call_number": "Ung 839.82 Vol:Ban",
6 | "circ_desk": {
7 | "desc": "Utlånet Ureal",
8 | "value": "DEFAULT_CIRC_DESK"
9 | },
10 | "description": null,
11 | "due_date": "2018-08-20T20:00:00Z",
12 | "item_barcode": "303011kj0",
13 | "item_policy": {
14 | "description": null,
15 | "value": null
16 | },
17 | "library": {
18 | "desc": "UiO HumSam-biblioteket",
19 | "value": "1030300"
20 | },
21 | "loan_date": "2018-07-23T20:25:26.347Z",
22 | "loan_id": "7378239410002204",
23 | "loan_status": "ACTIVE",
24 | "location_code": {
25 | "name": "UHS S-Litt",
26 | "value": "k00040"
27 | },
28 | "mms_id": "990006312214702204",
29 | "process_status": "NORMAL",
30 | "publication_year": "2000",
31 | "renewable": true,
32 | "title": "Bananboken K. Vollset ; [illustrasjoner: Motorfinger og Jim]",
33 | "user_id": "Dan Michael"
34 | }
35 | ],
36 | "total_record_count": 1
37 | }
--------------------------------------------------------------------------------
/src/Conf/JobInstance.php:
--------------------------------------------------------------------------------
1 | job = $job;
29 | $this->job_instance_id = $job_instance_id;
30 | parent::__construct($client);
31 | }
32 |
33 | /**
34 | * Check if we have the full representation of our data object.
35 | *
36 | * @param \stdClass $data
37 | *
38 | * @return bool
39 | */
40 | protected function isInitialized($data)
41 | {
42 | return isset($data->job_info);
43 | }
44 |
45 | /**
46 | * Generate the base URL for this resource.
47 | *
48 | * @return string
49 | */
50 | protected function urlBase()
51 | {
52 | return "/conf/jobs/{$this->job->job_id}/instances/{$this->job_instance_id}";
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/spec/Conf/JobInstancesSpec.php:
--------------------------------------------------------------------------------
1 | job_id = '1108569450000121';
16 | $this->beConstructedWith($client, $job);
17 | }
18 |
19 | public function it_provides_a_lazy_interface_to_jobinstance_objects(AlmaClient $client)
20 | {
21 | SpecHelper::expectNoRequests($client);
22 |
23 | $jobId = '1108569450000121';
24 | $instanceId = '1108569450000121';
25 | $jobInstance = $this->get($instanceId);
26 | $jobInstance->shouldBeAnInstanceOf(JobInstance::class);
27 | }
28 |
29 | public function it_provides_job_instances(AlmaClient $client)
30 | {
31 | $jobId = '1108569450000121';
32 | $client->getJSON("/conf/jobs/{$jobId}/instances?offset=0&limit=10")
33 | ->shouldBeCalled()
34 | ->willReturn(SpecHelper::getDummyData('jobinstances_response.json'));
35 |
36 | $this->all()->shouldBeArray();
37 | $this->all()[0]->shouldBeAnInstanceOf(JobInstance::class);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Users/Loans.php:
--------------------------------------------------------------------------------
1 | user = $user;
20 | }
21 |
22 | /**
23 | * Get resource.
24 | *
25 | * @param string $loan_id
26 | *
27 | * @return Loan
28 | */
29 | public function get($loan_id)
30 | {
31 | return Loan::make($this->client, $this->user, $loan_id);
32 | }
33 |
34 | /**
35 | * Convert a retrieved resource object to a model object.
36 | *
37 | * @param $data
38 | *
39 | * @return Loan
40 | */
41 | public function convertToResource($data)
42 | {
43 | return $this->get($data->loan_id)->init($data);
44 | }
45 |
46 | /**
47 | * Generate the base URL for this resource.
48 | *
49 | * @return string
50 | */
51 | protected function urlBase()
52 | {
53 | return sprintf('/users/%s/loans', $this->user->id);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/spec/TaskLists/RequestedResourcesSpec.php:
--------------------------------------------------------------------------------
1 | code = 'SOME_LIBRARY';
18 | $this->beConstructedWith($client, $library, 'DEFAULT_CIRC_DESK', [
19 | 'printed' => 'N',
20 | ]);
21 |
22 | $client->bibs = $bibs;
23 | $bibs->get('991120800814702204')
24 | ->shouldBeCalled()
25 | ->willReturn($bib);
26 |
27 | $client->getJSON('/task-lists/requested-resources?printed=N&library=SOME_LIBRARY&circ_desk=DEFAULT_CIRC_DESK&offset=0&limit=10')
28 | ->shouldBeCalled()
29 | ->willReturn(SpecHelper::getDummyData('requested-resources_response.json'));
30 |
31 | $result = $this->all();
32 |
33 | $result->shouldBeArray();
34 | $result->shouldHaveCount(1);
35 | $result[0]->shouldBeAnInstanceOf(RequestedResource::class);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Electronic/Collection.php:
--------------------------------------------------------------------------------
1 | collection_id = $collection_id;
23 | // FUTURE: $this->services = Services::make($this->client, $this);
24 | }
25 |
26 | /**
27 | * Generate the base URL for this resource.
28 | *
29 | * @return string
30 | */
31 | protected function urlBase()
32 | {
33 | return "/electronic/e-collections/{$this->collection_id}";
34 | }
35 |
36 | /**
37 | * Get the services for this collection.
38 | */
39 | // public function getServices()
40 | // {
41 | // return $this->services;
42 | // }
43 |
44 | /**
45 | * Check if we have the full representation of our data object.
46 | *
47 | * @param \stdClass $data
48 | *
49 | * @return bool
50 | */
51 | protected function isInitialized($data)
52 | {
53 | return isset($data->public_name);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Bibs/Portfolio.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
24 | $this->portfolio_id = $portfolio_id;
25 | }
26 |
27 | /**
28 | * Generate the base URL for this resource.
29 | *
30 | * @return string
31 | */
32 | protected function urlBase()
33 | {
34 | return "/bibs/{$this->bib->mms_id}/portfolios/{$this->portfolio_id}";
35 | }
36 |
37 | /**
38 | * Check if we have the full representation of our data object.
39 | *
40 | * @param \stdClass $data
41 | *
42 | * @return bool
43 | */
44 | protected function isInitialized($data)
45 | {
46 | return isset($data->linking_details);
47 | }
48 |
49 | public function getElectronicCollection()
50 | {
51 | $this->init();
52 |
53 | return new Collection($this->client, $this->data->electronic_collection->id->value);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Conf/Library.php:
--------------------------------------------------------------------------------
1 | code = $code;
29 | $this->locations = Locations::make($this->client, $this);
30 | }
31 |
32 | /**
33 | * Check if we have the full representation of our data object.
34 | * For libraries, it seems like we get the same data in the list
35 | * response as in the single-item response, so we just check some
36 | * random element.
37 | *
38 | * @param \stdClass $data
39 | *
40 | * @return bool
41 | */
42 | protected function isInitialized($data)
43 | {
44 | return isset($data->path);
45 | }
46 |
47 | /**
48 | * Generate the base URL for this resource.
49 | *
50 | * @return string
51 | */
52 | protected function urlBase()
53 | {
54 | return "/conf/libraries/{$this->code}";
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/spec/data/representation_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "library": {
3 | "value": "1030300",
4 | "desc": "UiO HumSam-biblioteket"
5 | },
6 | "id": "12216823140002204",
7 | "label": "High resolution TIFF images",
8 | "public_note": "Bare del 4 er digitalisert.",
9 | "usage_type": {
10 | "value": "PRESERVATION_MASTER",
11 | "desc": "Master"
12 | },
13 | "active": {
14 | "value": "true",
15 | "desc": "Active"
16 | },
17 | "author": null,
18 | "title": null,
19 | "volume": null,
20 | "issue": null,
21 | "date": null,
22 | "track": null,
23 | "number": null,
24 | "year": null,
25 | "access_rights_policy_id": {
26 | "value": "6863669220002204",
27 | "desc": "Fri tilgang!"
28 | },
29 | "delivery_url": "https://eu01.alma.exlibrisgroup.com/view/delivery/47BIBSYS_UBO/12216823140002204",
30 | "thumbnail_url": "https://eu01.alma.exlibrisgroup.com/view/delivery/thumbnail/47BIBSYS_UBO/12216823140002204",
31 | "repository": {
32 | "value": "Alma",
33 | "desc": null
34 | },
35 | "created_by": "System",
36 | "created_date": "2018-09-05Z",
37 | "last_modified_by": "System",
38 | "last_modified_date": "2018-09-13Z",
39 | "files": {
40 | "value": null,
41 | "total_record_count": 96,
42 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999814378424702204/representations/12216823140002204/files"
43 | },
44 | "is_remote": false,
45 | "link": null
46 | }
47 |
--------------------------------------------------------------------------------
/src/Users/Requests.php:
--------------------------------------------------------------------------------
1 | _urlBase = $url;
30 | }
31 |
32 | /**
33 | * Convert a data element to a resource object.
34 | *
35 | * @param $data
36 | *
37 | * @return Request
38 | */
39 | protected function convertToResource($data)
40 | {
41 | return Request::make($this->client, User::make($this->client, $data->user_primary_id), $data->request_id)
42 | ->init($data);
43 | }
44 |
45 | /**
46 | * Generate the base URL for this resource.
47 | *
48 | * @return string
49 | */
50 | protected function urlBase()
51 | {
52 | return $this->_urlBase;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Users/Fee.php:
--------------------------------------------------------------------------------
1 | user = $user;
24 | $this->id = $id;
25 | }
26 |
27 | /**
28 | * Generate the base URL for this resource.
29 | *
30 | * @return string
31 | */
32 | protected function urlBase()
33 | {
34 | return sprintf('/users/%s/fees/%s', rawurlencode($this->user->id), $this->id);
35 | }
36 |
37 | /**
38 | * Check if we have the full representation of our data object.
39 | *
40 | * @param \stdClass $data
41 | *
42 | * @return bool
43 | */
44 | protected function isInitialized($data)
45 | {
46 | return isset($data->link);
47 | }
48 |
49 | /**
50 | * Get the related Item, if any.
51 | *
52 | * @return Item|null
53 | */
54 | public function getItem()
55 | {
56 | if (isset($this->barcode)) {
57 | return $this->client->items->fromBarcode($this->barcode);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/spec/Conf/LibrariesSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client);
16 | }
17 |
18 | public function it_is_muh()
19 | {
20 | $this->shouldBeAnInstanceOf(Libraries::class);
21 | $this->shouldImplement(\Countable::class);
22 | $this->shouldImplement(\Iterator::class);
23 | }
24 |
25 | public function it_provides_a_lazy_interface_to_libary_objects(AlmaClient $client)
26 | {
27 | SpecHelper::expectNoRequests($client);
28 |
29 | $libraryCode = 'THAT_LIBRARY';
30 | $library = $this->get($libraryCode);
31 |
32 | $library->shouldBeAnInstanceOf(Library::class);
33 | $library->code->shouldBe($libraryCode);
34 | }
35 |
36 | public function it_provides_libraries(AlmaClient $client)
37 | {
38 | $client->getJSON('/conf/libraries')
39 | ->shouldBeCalled()
40 | ->willReturn(SpecHelper::getDummyData('libraries_response.json'));
41 |
42 | $this->shouldHaveCount(27);
43 | $this->all()->shouldBeArray();
44 | $this->all()[0]->shouldBeAnInstanceOf(Library::class);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/spec/Bibs/ElectronicCollectionsSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = 'abc';
17 | $this->beConstructedWith($client, $bib);
18 | }
19 |
20 | public function it_is_initializable()
21 | {
22 | $this->shouldHaveType(ElectronicCollections::class);
23 | }
24 |
25 | protected function expectRequest($client)
26 | {
27 | $client->getJSON('/bibs/abc/e-collections')
28 | ->shouldBeCalled()
29 | ->willReturn(SpecHelper::getDummyData('e-collections_response.json'));
30 | }
31 |
32 | public function it_is_countable(AlmaClient $client)
33 | {
34 | $this->expectRequest($client);
35 |
36 | $this->shouldHaveCount(1);
37 | }
38 |
39 | public function it_provides_basic_data_without_loading_the_full_record(AlmaClient $client)
40 | {
41 | $this->expectRequest($client);
42 |
43 | $c = $this->all()[0];
44 |
45 | $c->shouldHaveType(Collection::class);
46 | $c->public_name->shouldBe('SpringerLink Books Complete');
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/spec/Bibs/PortfolioSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = 'abc';
17 | $portfolio_id = '123';
18 | $this->beConstructedWith($client, $bib, $portfolio_id);
19 | }
20 |
21 | public function it_is_initializable()
22 | {
23 | $this->shouldHaveType(Portfolio::class);
24 | }
25 |
26 | protected function expectRequest($client)
27 | {
28 | $client->getJSON('/bibs/abc/portfolios/123')
29 | ->shouldBeCalled()
30 | ->willReturn(SpecHelper::getDummyData('portfolio_response.json'));
31 | }
32 |
33 | public function it_fetches_data_when_needed(AlmaClient $client)
34 | {
35 | $this->expectRequest($client);
36 |
37 | $this->availability->desc->shouldBe('Available');
38 | }
39 |
40 | public function it_belongs_to_collection(AlmaClient $client)
41 | {
42 | $this->expectRequest($client);
43 |
44 | $this->getElectronicCollection()->shouldHaveType(Collection::class);
45 | $this->electronic_collection->shouldHaveType(Collection::class);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Bibs/Representation.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
26 | $this->representation_id = $representation_id;
27 | $this->files = Files::make($this->client, $bib, $this);
28 | }
29 |
30 | /**
31 | * Generate the base URL for this resource.
32 | *
33 | * @return string
34 | */
35 | protected function urlBase()
36 | {
37 | return "/bibs/{$this->bib->mms_id}/representations/{$this->representation_id}";
38 | }
39 |
40 | /**
41 | * Get the files for this representation.
42 | */
43 | public function getFiles()
44 | {
45 | return $this->files;
46 | }
47 |
48 | /**
49 | * Check if we have the full representation of our data object.
50 | *
51 | * @param \stdClass $data
52 | *
53 | * @return bool
54 | */
55 | protected function isInitialized($data)
56 | {
57 | return isset($data->delivery_url);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Conf/Jobs.php:
--------------------------------------------------------------------------------
1 | client, $job_id);
38 | }
39 |
40 | /**
41 | * Convert a data element to a resource object.
42 | *
43 | * @param $data
44 | *
45 | * @return Job
46 | */
47 | protected function convertToResource($data)
48 | {
49 | return Job::make($this->client, $data->id)
50 | ->init($data);
51 | }
52 |
53 | /**
54 | * Generate the base URL for this resource.
55 | *
56 | * @return string
57 | */
58 | protected function urlBase()
59 | {
60 | return '/conf/jobs';
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/spec/Users/LoansSpec.php:
--------------------------------------------------------------------------------
1 | id = '123435';
17 | $this->beConstructedWith($client, $user);
18 | }
19 |
20 | public function it_is_initializable()
21 | {
22 | $this->shouldHaveType(Loans::class);
23 | }
24 |
25 | public function it_yields_loans(AlmaClient $client)
26 | {
27 | $client->getJSON('/users/123435/loans?offset=0&limit=10')
28 | ->shouldBeCalled()
29 | ->willReturn(SpecHelper::getDummyData('loans_response.json'));
30 |
31 | $this->rewind();
32 | $this->valid()->shouldBe(true);
33 | $this->current()->shouldBeAnInstanceOf(Loan::class);
34 |
35 | $this->shouldHaveCount(2);
36 | }
37 |
38 | public function it_can_be_empty(AlmaClient $client)
39 | {
40 | $client->getJSON('/users/123435/loans?offset=0&limit=10')
41 | ->shouldBeCalled()
42 | ->willReturn(SpecHelper::getDummyData('zero_loans_response.json'));
43 |
44 | $this->rewind();
45 | $this->valid()->shouldBe(false);
46 |
47 | $this->shouldHaveCount(0);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/spec/Users/FeesSpec.php:
--------------------------------------------------------------------------------
1 | id = '123435';
17 | $this->beConstructedWith($client, $user);
18 | }
19 |
20 | public function it_is_initializable()
21 | {
22 | $this->shouldHaveType(Fees::class);
23 | }
24 |
25 | public function it_yields_fees(AlmaClient $client)
26 | {
27 | $client->getJSON('/users/123435/fees')
28 | ->shouldBeCalled()
29 | ->willReturn(SpecHelper::getDummyData('fees_response.json'));
30 |
31 | $this->total_sum->shouldBe(750);
32 |
33 | $this->rewind();
34 | $this->valid()->shouldBe(true);
35 | $this->current()->shouldBeAnInstanceOf(Fee::class);
36 |
37 | $this->shouldHaveCount(1);
38 | }
39 |
40 | public function it_can_be_empty(AlmaClient $client)
41 | {
42 | $client->getJSON('/users/123435/fees')
43 | ->shouldBeCalled()
44 | ->willReturn(SpecHelper::getDummyData('zero_fees_response.json'));
45 |
46 | $this->rewind();
47 | $this->valid()->shouldBe(false);
48 |
49 | $this->shouldHaveCount(0);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Conf/Job.php:
--------------------------------------------------------------------------------
1 | job_id = $job_id;
29 | $this->instances = new JobInstances($client, $this);
30 | }
31 |
32 | /**
33 | * Submit the job for running.
34 | *
35 | * @return string The API response body
36 | */
37 | public function submit()
38 | {
39 | return $this->client->post($this->url() . '?op=run', json_encode($this->jsonSerialize()));
40 | }
41 |
42 | /**
43 | * Check if we have the full representation of our data object.
44 | *
45 | * @param \stdClass $data
46 | *
47 | * @return bool
48 | */
49 | protected function isInitialized($data)
50 | {
51 | return isset($data->name);
52 | }
53 |
54 | /**
55 | * Generate the base URL for this resource.
56 | *
57 | * @return string
58 | */
59 | protected function urlBase()
60 | {
61 | return "/conf/jobs/{$this->job_id}";
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Bibs/File.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
34 | $this->representation = $representation;
35 | $this->file_id = $file_id;
36 | }
37 |
38 | /**
39 | * Generate the base URL for this resource.
40 | *
41 | * @return string
42 | */
43 | protected function urlBase()
44 | {
45 | return "/bibs/{$this->bib->mms_id}/representations/{$this->representation->representation_id}/files/{$this->file_id}";
46 | }
47 |
48 | /**
49 | * Check if we have the full representation of our data object.
50 | *
51 | * @param \stdClass $data
52 | *
53 | * @return bool
54 | */
55 | protected function isInitialized($data)
56 | {
57 | return isset($data->path);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Conf/Libraries.php:
--------------------------------------------------------------------------------
1 | client, $code);
38 | }
39 |
40 | /**
41 | * Convert a data element to a resource object.
42 | *
43 | * @param $data
44 | *
45 | * @return Library
46 | */
47 | protected function convertToResource($data)
48 | {
49 | return Library::make($this->client, $data->code)
50 | ->init($data);
51 | }
52 |
53 | /**
54 | * Generate the base URL for this resource.
55 | *
56 | * @return string
57 | */
58 | protected function urlBase()
59 | {
60 | return '/conf/libraries';
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/spec/data/jobinstances_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "total_record_count": 1,
3 | "job_instance": [
4 | {
5 | "link": "string",
6 | "id": "1108569450000121",
7 | "external_id": "1108569450000121",
8 | "name": "Export Physical Items - war and love - 04/15/2015 16:07",
9 | "submitted_by": {
10 | "desc": "string",
11 | "value": "exl_impl"
12 | },
13 | "submit_time": "2015-04-15T13:07:40.800Z",
14 | "start_time": "2015-04-15T13:07:40.868Z",
15 | "end_time": "2015-04-15T13:07:44.359Z",
16 | "progress": 100,
17 | "status": {
18 | "desc": "string",
19 | "value": "QUEUED"
20 | },
21 | "status_date": "2015-07-20",
22 | "alert": [
23 | {
24 | "desc": "string",
25 | "value": "alert_general_success"
26 | }
27 | ],
28 | "counter": [
29 | {
30 | "type": {
31 | "desc": "string",
32 | "value": "4"
33 | },
34 | "value": "string"
35 | }
36 | ],
37 | "action": [
38 | {
39 | "link": "string",
40 | "type": {
41 | "desc": "string",
42 | "value": "CREATE_SET"
43 | },
44 | "population": {
45 | "desc": "string",
46 | "value": "string"
47 | },
48 | "members": 0
49 | }
50 | ],
51 | "job_info": {
52 | "link": "string",
53 | "id": "1108569450000121",
54 | "name": "Export Physical Items - war and love - 04/15/2015 16:07",
55 | "description": "string",
56 | "type": {
57 | "desc": "string",
58 | "value": "CREATE_SET"
59 | },
60 | "category": {
61 | "desc": "string",
62 | "value": "NORMALIZATION"
63 | }
64 | }
65 | }
66 | ]
67 | }
--------------------------------------------------------------------------------
/spec/data/holdings_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "bib_data": {
3 | "author": "Vollset, K.",
4 | "date_of_publication": "2000",
5 | "isbn": "8247806290",
6 | "issn": null,
7 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/990006312214702204",
8 | "mms_id": "990006312214702204",
9 | "network_number": [
10 | "(NO-TrBIB)092093302",
11 | "(NO-TrBIB)000631221",
12 | "000631221-47bibsys_network",
13 | "(EXLNZ-47BIBSYS_NETWORK)990006312214702201"
14 | ],
15 | "place_of_publication": "[Oslo]",
16 | "publisher": "Gyldendal Tiden",
17 | "title": "Bananboken"
18 | },
19 | "holding": [
20 | {
21 | "holding_id": "2221159990000121",
22 | "library": {
23 | "desc": "BURNS",
24 | "value": "65144020000121"
25 | },
26 | "link": "/almaws/v1/bibs/99100383900121/holdings/2221159990000121",
27 | "location": {
28 | "desc": "UNASSIGNED location",
29 | "value": "UNASSIGNED"
30 | }
31 | },
32 | {
33 | "holding_id": "2221410000000121",
34 | "library": {
35 | "desc": "Main Library",
36 | "value": "5867020000121"
37 | },
38 | "link": "/almaws/v1/bibs/99100383900121/holdings/2221410000000121",
39 | "location": {
40 | "desc": "Microforms",
41 | "value": "MICR"
42 | }
43 | }
44 | ],
45 | "total_record_count": 1
46 | }
--------------------------------------------------------------------------------
/src/TaskLists/RequestedResources.php:
--------------------------------------------------------------------------------
1 | library = $library;
26 | $params['library'] = $library->code;
27 | $params['circ_desk'] = $circ_desk;
28 | $this->params = $params;
29 | }
30 |
31 | /**
32 | * Generate the base URL for this resource.
33 | *
34 | * @return string
35 | */
36 | protected function urlBase()
37 | {
38 | return '/task-lists/requested-resources';
39 | }
40 |
41 | /**
42 | * Convert a data element to a resource object.
43 | *
44 | * @param $data
45 | *
46 | * @return mixed
47 | */
48 | protected function convertToResource($data)
49 | {
50 | $bib = $this->client->bibs->get($data->resource_metadata->mms_id->value);
51 |
52 | return RequestedResource::make($this->client, $this->library, $this->params['circ_desk'], $bib)
53 | ->init($data);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/spec/Bibs/RepresentationSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = 'abc';
17 | $representation_id = '123';
18 | $this->beConstructedWith($client, $bib, $representation_id);
19 | }
20 |
21 | protected function expectRequest($client)
22 | {
23 | $client->getJSON('/bibs/abc/representations/123')
24 | ->shouldBeCalled()
25 | ->willReturn(SpecHelper::getDummyData('representation_response.json'));
26 | }
27 |
28 | public function it_is_initializable()
29 | {
30 | $this->shouldHaveType(Representation::class);
31 | }
32 |
33 | public function it_fetches_data_when_needed(AlmaClient $client)
34 | {
35 | $this->expectRequest($client);
36 |
37 | $this->label->shouldBe('High resolution TIFF images');
38 | }
39 |
40 | public function it_has_files(AlmaClient $client)
41 | {
42 | $client->getJSON('/bibs/abc/representations/123/files')
43 | ->shouldBeCalled()
44 | ->willReturn(SpecHelper::getDummyData('files_response.json'));
45 |
46 | $files = $this->files;
47 | $files->shouldHaveCount(96);
48 |
49 | $files->rewind();
50 | $files->valid()->shouldBe(true);
51 | $files->current()->shouldHaveType(File::class);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Users/Loan.php:
--------------------------------------------------------------------------------
1 | user = $user;
24 | $this->loan_id = $loan_id;
25 | }
26 |
27 | /**
28 | * Generate the base URL for this resource.
29 | *
30 | * @return string
31 | */
32 | protected function urlBase()
33 | {
34 | return sprintf('/users/%s/loans/%s', rawurlencode($this->user->id), $this->loan_id);
35 | }
36 |
37 | /**
38 | * Check if we have the full representation of our data object.
39 | *
40 | * @param \stdClass $data
41 | *
42 | * @return bool
43 | */
44 | protected function isInitialized($data)
45 | {
46 | return isset($data->loan_id);
47 | }
48 |
49 | /**
50 | * Get the Item on loan. Since the response from the loan(s) API does not
51 | * include the `holding_id` and `item_pid`, we cannot initiate an Item object
52 | * directly, so we have to lookup the barcode instead.
53 | *
54 | * @see https://developers.exlibrisgroup.com/discussions#!/forum/posts/list/1397.page
55 | *
56 | * @return Item
57 | */
58 | public function getItem()
59 | {
60 | return $this->client->items->fromBarcode($this->item_barcode);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Model/PaginatedListGenerator.php:
--------------------------------------------------------------------------------
1 | position > 0) {
18 | throw new \Exception('Cannot rewind a generator that was already run');
19 | }
20 | }
21 |
22 | /**
23 | * Checks if current position is valid.
24 | *
25 | * @link http://php.net/manual/en/iterator.valid.php
26 | */
27 | public function valid(): bool
28 | {
29 | if (!isset($this->resources[0])) {
30 | $this->fetchBatch();
31 | }
32 |
33 | return isset($this->resources[0]);
34 | }
35 |
36 | /**
37 | * Return the current element.
38 | *
39 | * @link http://php.net/manual/en/iterator.current.php
40 | */
41 | public function current(): mixed
42 | {
43 | return array_shift($this->resources);
44 | }
45 |
46 | /**
47 | * Move forward to next element.
48 | *
49 | * @link http://php.net/manual/en/iterator.next.php
50 | */
51 | public function next(): void
52 | {
53 | $this->position++;
54 | }
55 |
56 | /**
57 | * Return the key of the current element.
58 | *
59 | * @link http://php.net/manual/en/iterator.key.php
60 | *
61 | * @return int|null Scalar on success, or null on failure.
62 | */
63 | public function key(): mixed
64 | {
65 | return $this->position;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Users/Fees.php:
--------------------------------------------------------------------------------
1 | user = $user;
35 | }
36 |
37 | /**
38 | * Get a single Fee by id.
39 | *
40 | * @param string $id
41 | *
42 | * @return Fee
43 | */
44 | public function get($id)
45 | {
46 | return Fee::make($this->client, $this->user, $id);
47 | }
48 |
49 | /**
50 | * Convert a retrieved resource object to a model object.
51 | *
52 | * @param $data
53 | *
54 | * @return Fee
55 | */
56 | public function convertToResource($data)
57 | {
58 | return $this->get($data->id)->init($data);
59 | }
60 |
61 | /**
62 | * Generate the base URL for this resource.
63 | *
64 | * @return string
65 | */
66 | protected function urlBase()
67 | {
68 | return sprintf('/users/%s/fees', rawurlencode($this->user->id));
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Bibs/Portfolios.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
32 | }
33 |
34 | /**
35 | * Get a single portfolio record by id.
36 | *
37 | * @param string $id
38 | *
39 | * @return Portfolio
40 | */
41 | public function get($id)
42 | {
43 | return Portfolio::make($this->client, $this->bib, $id);
44 | }
45 |
46 | /**
47 | * Convert a data element to a resource object.
48 | *
49 | * @param $data
50 | *
51 | * @return Portfolio
52 | */
53 | protected function convertToResource($data)
54 | {
55 | return Portfolio::make($this->client, $this->bib, $data->id)
56 | ->init($data);
57 | }
58 |
59 | /**
60 | * Generate the base URL for this resource.
61 | *
62 | * @return string
63 | */
64 | protected function urlBase()
65 | {
66 | return "/bibs/{$this->bib->mms_id}/portfolios";
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Model/PaginatedList.php:
--------------------------------------------------------------------------------
1 | position = 0;
20 | }
21 |
22 | /**
23 | * Checks if current position is valid.
24 | *
25 | * @link http://php.net/manual/en/iterator.valid.php
26 | *
27 | * @return bool
28 | */
29 | public function valid()
30 | {
31 | if (!isset($this->resources[$this->position])) {
32 | $this->fetchBatch();
33 | }
34 |
35 | return isset($this->resources[$this->position]);
36 | }
37 |
38 | /**
39 | * Return the current element.
40 | *
41 | * @link http://php.net/manual/en/iterator.current.php
42 | *
43 | * @return mixed
44 | */
45 | public function current()
46 | {
47 | return $this->resources[$this->position];
48 | }
49 |
50 | /**
51 | * Move forward to next element.
52 | *
53 | * @link http://php.net/manual/en/iterator.next.php
54 | *
55 | * @return void
56 | */
57 | public function next()
58 | {
59 | $this->position++;
60 | }
61 |
62 | /**
63 | * Return the key of the current element.
64 | *
65 | * @link http://php.net/manual/en/iterator.key.php
66 | *
67 | * @return int|null Scalar on success, or null on failure.
68 | */
69 | public function key()
70 | {
71 | return $this->position;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/spec/SpecHelper.php:
--------------------------------------------------------------------------------
1 | getJSON(Argument::any(), Argument::any())
32 | ->shouldNotBeCalled();
33 |
34 | $client->getXML(Argument::any(), Argument::any())
35 | ->shouldNotBeCalled();
36 | }
37 |
38 | public static function makeExceptionResponse(
39 | $body,
40 | $code = 400,
41 | $contentType = 'application/json;charset=utf-8',
42 | $cls = ClientErrorException::class
43 | ) {
44 | $requestFactory = new RequestFactory();
45 | $responseFactory = new ResponseFactory();
46 |
47 | return new $cls(
48 | 'Error 400',
49 | $requestFactory->createRequest('GET', ''),
50 | $responseFactory->createResponse($code, 'Bad Request')
51 | ->withHeader('Content-Type', $contentType)
52 | ->withBody(stream_for($body))
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Conf/JobInstances.php:
--------------------------------------------------------------------------------
1 | job = $job;
31 | }
32 |
33 | /**
34 | * Get a single Job Instance by its instance_id.
35 | *
36 | * @param string $instance_id
37 | *
38 | * @return JobInstance
39 | */
40 | public function get(string $instance_id)
41 | {
42 | return JobInstance::make($this->client, $this->job, $instance_id);
43 | }
44 |
45 | /**
46 | * Convert a data element to a resource object.
47 | *
48 | * @param $data
49 | *
50 | * @return JobInstance
51 | */
52 | protected function convertToResource($data)
53 | {
54 | return JobInstance::make($this->client, $this->job, $data->id)
55 | ->init($data);
56 | }
57 |
58 | /**
59 | * Generate the base URL for this resource.
60 | *
61 | * @return string
62 | */
63 | protected function urlBase()
64 | {
65 | return "/conf/jobs/{$this->job->job_id}/instances";
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/spec/Bibs/HoldingSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = 'abc';
18 | $holdings_id = '123';
19 | $this->beConstructedWith($client, $bib, $holdings_id);
20 | }
21 |
22 | protected function expectRequest($client)
23 | {
24 | $client->getXML('/bibs/abc/holdings/123')
25 | ->shouldBeCalled()
26 | ->willReturn(SpecHelper::getDummyData('holding_response.xml'));
27 | }
28 |
29 | public function it_is_initializable()
30 | {
31 | $this->shouldHaveType(Holding::class);
32 | }
33 |
34 | public function it_fetches_record_data_when_needed(AlmaClient $client)
35 | {
36 | $this->expectRequest($client);
37 |
38 | $this->created_by->shouldBe('import');
39 | $this->created_date->shouldBe('2015-11-05Z');
40 |
41 | $this->record->shouldHaveType(Record::class);
42 | }
43 |
44 | public function it_has_items(AlmaClient $client)
45 | {
46 | $client->getJSON('/bibs/abc/holdings/123/items')
47 | ->shouldBeCalled()
48 | ->willReturn(SpecHelper::getDummyData('items_response.json'));
49 |
50 | $items = $this->items;
51 | $items->shouldHaveCount(9);
52 |
53 | $items->rewind();
54 | $items->valid()->shouldBe(true);
55 | $items->current()->shouldHaveType(Item::class);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Bibs/Representations.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
32 | }
33 |
34 | /**
35 | * Get a single representation record by id.
36 | *
37 | * @param string $id
38 | *
39 | * @return Representation
40 | */
41 | public function get($id)
42 | {
43 | return Representation::make($this->client, $this->bib, $id);
44 | }
45 |
46 | /**
47 | * Convert a data element to a resource object.
48 | *
49 | * @param $data
50 | *
51 | * @return Representation
52 | */
53 | protected function convertToResource($data)
54 | {
55 | return Representation::make($this->client, $this->bib, $data->id)
56 | ->init($data);
57 | }
58 |
59 | /**
60 | * Generate the base URL for this resource.
61 | *
62 | * @return string
63 | */
64 | protected function urlBase()
65 | {
66 | return "/bibs/{$this->bib->mms_id}/representations";
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/spec/data/e-collection_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "61173723710002204",
3 | "is_local": false,
4 | "public_name": "SpringerLink Books Complete",
5 | "public_name_override": "",
6 | "description": "",
7 | "internal_description": "",
8 | "library": {
9 | "value": "",
10 | "link": null
11 | },
12 | "type": {
13 | "value": "0",
14 | "desc": "Selective package"
15 | },
16 | "interface": {
17 | "name": "Springer Link",
18 | "vendor": null
19 | },
20 | "process_type": {
21 | "value": "",
22 | "desc": null
23 | },
24 | "access_type": {
25 | "value": "",
26 | "desc": null
27 | },
28 | "po_line": {
29 | "value": "",
30 | "link": null
31 | },
32 | "activation_date": "2010-09-17Z",
33 | "license": {
34 | "value": "070001039",
35 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/acq/licenses/070001039"
36 | },
37 | "alternative_title": "",
38 | "source": "",
39 | "creator": "",
40 | "url": "http://link.springer.com",
41 | "url_override": "",
42 | "free": {
43 | "value": "",
44 | "desc": null
45 | },
46 | "proxy_enabled": {
47 | "value": "",
48 | "desc": null
49 | },
50 | "proxy": "",
51 | "language": {
52 | "value": "",
53 | "desc": null
54 | },
55 | "category": "",
56 | "resource_metadata": {
57 | "mms_id": {
58 | "value": "999919849150002204",
59 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999919849150002204"
60 | },
61 | "title": "SpringerLink Books Complete",
62 | "author": "",
63 | "issn": ""
64 | },
65 | "portfolios": {
66 | "value": 55900,
67 | "link": null
68 | },
69 | "authentication_note": "",
70 | "public_note": "",
71 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/electronic/e-collections/61173723710002204"
72 | }
73 |
--------------------------------------------------------------------------------
/src/Bibs/ElectronicCollections.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
33 | }
34 |
35 | /**
36 | * Get a single electronic collection record by id.
37 | *
38 | * @param string $id
39 | *
40 | * @return Representation
41 | */
42 | public function get($id)
43 | {
44 | return Collection::make($this->client, $id);
45 | }
46 |
47 | /**
48 | * Convert a data element to a resource object.
49 | *
50 | * @param $data
51 | *
52 | * @return Representation
53 | */
54 | protected function convertToResource($data)
55 | {
56 | return Collection::make($this->client, $data->id)
57 | ->init($data);
58 | }
59 |
60 | /**
61 | * Generate the base URL for this resource.
62 | *
63 | * @return string
64 | */
65 | protected function urlBase()
66 | {
67 | return "/bibs/{$this->bib->mms_id}/e-collections";
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Bibs/Holdings.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
35 | }
36 |
37 | /**
38 | * Get a single holding record by id.
39 | *
40 | * @param string $holding_id
41 | *
42 | * @return Holding
43 | */
44 | public function get($holding_id)
45 | {
46 | return Holding::make($this->client, $this->bib, $holding_id);
47 | }
48 |
49 | /**
50 | * Convert a data element to a resource object.
51 | *
52 | * @param $data
53 | *
54 | * @return Holding
55 | */
56 | protected function convertToResource($data)
57 | {
58 | return Holding::make($this->client, $this->bib, $data->holding_id)
59 | ->init($data);
60 | }
61 |
62 | /**
63 | * Generate the base URL for this resource.
64 | *
65 | * @return string
66 | */
67 | protected function urlBase()
68 | {
69 | return "/bibs/{$this->bib->mms_id}/holdings";
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Conf/Locations.php:
--------------------------------------------------------------------------------
1 | library = $library;
35 | }
36 |
37 | /**
38 | * Get a single location by its location code.
39 | *
40 | * @param string $code
41 | *
42 | * @return Location
43 | */
44 | public function get($code)
45 | {
46 | return Location::make($this->client, $this->library, $code);
47 | }
48 |
49 | /**
50 | * Convert a data element to a resource object.
51 | *
52 | * @param $data
53 | *
54 | * @return Location
55 | */
56 | protected function convertToResource($data)
57 | {
58 | return Location::make($this->client, $this->library, $data->code)
59 | ->init($data);
60 | }
61 |
62 | /**
63 | * Generate the base URL for this resource.
64 | *
65 | * @return string
66 | */
67 | protected function urlBase()
68 | {
69 | return "/conf/libraries/{$this->library->code}/locations";
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/spec/data/representations_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "representation": [
3 | {
4 | "id": "12216823130002204",
5 | "label": "PDF",
6 | "active": {
7 | "value": "true",
8 | "desc": "Active"
9 | },
10 | "author": null,
11 | "title": null,
12 | "volume": null,
13 | "issue": null,
14 | "date": null,
15 | "track": null,
16 | "number": null,
17 | "year": null,
18 | "repository": {
19 | "value": "Alma",
20 | "desc": null
21 | },
22 | "files": {
23 | "value": null,
24 | "total_record_count": 1,
25 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999814378424702204/representations/12216823130002204/files"
26 | },
27 | "is_remote": false,
28 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999814378424702204/representations/12216823130002204"
29 | },
30 | {
31 | "id": "12216823140002204",
32 | "label": "High resolution TIFF images",
33 | "active": {
34 | "value": "true",
35 | "desc": "Active"
36 | },
37 | "author": null,
38 | "title": null,
39 | "volume": null,
40 | "issue": null,
41 | "date": null,
42 | "track": null,
43 | "number": null,
44 | "year": null,
45 | "repository": {
46 | "value": "Alma",
47 | "desc": null
48 | },
49 | "files": {
50 | "value": null,
51 | "total_record_count": 96,
52 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999814378424702204/representations/12216823140002204/files"
53 | },
54 | "is_remote": false,
55 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999814378424702204/representations/12216823140002204"
56 | }
57 | ],
58 | "total_record_count": 2
59 | }
60 |
--------------------------------------------------------------------------------
/config/alma.php:
--------------------------------------------------------------------------------
1 | env('ALMA_REGION', 'eu'),
11 |
12 | /*
13 | |--------------------------------------------------------------------------
14 | | Institution zone settings
15 | |--------------------------------------------------------------------------
16 | */
17 | 'iz' => [
18 | // API key for institution zone
19 | 'key' => env('ALMA_IZ_KEY'),
20 |
21 | // SRU URL for institution zone
22 | 'sru' => env('ALMA_IZ_SRU_URL'),
23 |
24 | // Entry point URL. This only needs to be specified if you use a proxy
25 | // or other non-standard entry point.
26 | 'entrypoint' => null,
27 |
28 | // Optional list of extra headers to send with each request.
29 | 'headers' => [
30 | // 'x-proxy-auth' => 'custom proxy auth'
31 | ],
32 | ],
33 |
34 | /*
35 | |--------------------------------------------------------------------------
36 | | Network zone settings
37 | |--------------------------------------------------------------------------
38 | */
39 | 'nz' => [
40 | // API key for institution zone
41 | 'key' => env('ALMA_NZ_KEY'),
42 |
43 | // SRU URL for institution zone
44 | 'sru' => env('ALMA_NZ_SRU_URL'),
45 |
46 | // Entry point URL. This only needs to be specified if you use a proxy
47 | // or other non-standard entry point.
48 | 'entrypoint' => null,
49 |
50 | // Optional list of extra headers to send with each request.
51 | 'headers' => [
52 | // 'x-proxy-auth' => 'custom proxy auth'
53 | ],
54 | ],
55 | ];
56 |
--------------------------------------------------------------------------------
/spec/data/holding_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "anies": [
3 | "\n\n \n 00370nx a2200133ui 4500\n h449730-47bibsys_ubo\n 000631221-47bibsys_ubo\n ta\n 1511020l||||||||4 uu\n kat\n \n 000631221\n (NO-TrBIB)\n \n \n 00kj16342-47bibsys_ubo\n \n \n 1030300\n k00040\n Ung 839.82 Vol:Ban\n \n \n 1030300\n k00040\n Ung 839.82 Vol:Ban\n 0\n 0\n 2015-11-02\n \n \n 00kj16342\n 20000529\n kat\n 303011kj0\n 00kj16342\n BOOK\n \n \n"
4 | ],
5 | "created_by": "import",
6 | "created_date": "2015-11-05Z",
7 | "holding_id": "22163771200002204",
8 | "originating_system": "ILS",
9 | "originating_system_id": "h449730-47bibsys_ubo",
10 | "suppress_from_publishing": "false"
11 | }
--------------------------------------------------------------------------------
/src/Bibs/Files.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
43 | $this->representation = $representation;
44 | }
45 |
46 | /**
47 | * Convert a data element to a resource object.
48 | *
49 | * @param $data
50 | *
51 | * @return File
52 | */
53 | protected function convertToResource($data)
54 | {
55 | return File::make($this->client, $this->bib, $this->representation, $data->pid)
56 | ->init($data);
57 | }
58 |
59 | /**
60 | * Generate the base URL for this resource.
61 | *
62 | * @return string
63 | */
64 | protected function urlBase()
65 | {
66 | return "/bibs/{$this->bib->mms_id}/representations/{$this->representation->representation_id}/files";
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/TaskLists/LendingRequests.php:
--------------------------------------------------------------------------------
1 | library = $library;
35 | $params['library'] = $library->code;
36 | $this->params = $params;
37 | }
38 |
39 | /**
40 | * Generate the base URL for this resource.
41 | *
42 | * @return string
43 | */
44 | protected function urlBase()
45 | {
46 | return '/task-lists/rs/lending-requests';
47 | }
48 |
49 | /**
50 | * Convert a data element to a resource object.
51 | *
52 | * @param $data
53 | *
54 | * @return mixed
55 | */
56 | protected function convertToResource($data)
57 | {
58 | return ResourceSharingRequest::make($this->client, $data->request_id)
59 | ->init($data);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "scriptotek/alma-client",
3 | "type": "library",
4 | "description": "Package for interacting with some of the Alma APIs",
5 | "homepage": "http://github.com/scriptotek/php-alma-client",
6 | "keywords": ["alma"],
7 | "minimum-stability": "dev",
8 | "prefer-stable": true,
9 | "require": {
10 | "php" : ">=7.1",
11 | "ext-json": "*",
12 | "scriptotek/marc": "^2.0",
13 | "danmichaelo/quitesimplexmlelement": "^1.0",
14 | "scriptotek/sru-client": "^0.7.1",
15 | "psr/http-message": "^1.0",
16 | "psr/http-client-implementation": "^1.0",
17 | "psr/http-factory-implementation": "^1.0",
18 | "http-interop/http-factory-discovery": "^1.4",
19 | "php-http/client-common": "^1.9 || ^2.0",
20 | "symfony/polyfill-php73": "^1.11",
21 | "friends-of-phpspec/phpspec-expect": "^4.0"
22 | },
23 | "require-dev": {
24 | "phpspec/phpspec": "^5.0 || ^6.0 || ^7.0",
25 | "wp-cli/php-cli-tools": "^0.11.1",
26 | "php-http/mock-client": "^1.0",
27 | "php-http/guzzle6-adapter": "^1.1 || ^2.0",
28 | "http-interop/http-factory-guzzle": "^1.0",
29 | "squizlabs/php_codesniffer": "^3.3"
30 | },
31 | "license": "MIT",
32 | "authors": [
33 | {
34 | "name": "Dan Michael O. Heggø",
35 | "email": "danmichaelo@gmail.com"
36 | }
37 | ],
38 | "autoload": {
39 | "psr-4": {
40 | "Scriptotek\\Alma\\": "src/"
41 | }
42 | },
43 | "autoload-dev": {
44 | "psr-4": {
45 | "spec\\Scriptotek\\Alma\\": "spec/"
46 | }
47 | },
48 | "extra": {
49 | "laravel": {
50 | "providers": [
51 | "Scriptotek\\Alma\\Laravel\\ServiceProvider"
52 | ],
53 | "aliases": {
54 | "Alma": "Scriptotek\\Alma\\Laravel\\Facade"
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Analytics/Row.php:
--------------------------------------------------------------------------------
1 | headers = $headers;
19 | foreach ($headers as $idx => $header) {
20 | $value = $data->text('rowset:Column' . ($idx + 1)) ?: null;
21 | $this->byIndex[$idx] = $value;
22 | $this->byHeader[$header] = $value;
23 | }
24 | }
25 |
26 | public function __get($name)
27 | {
28 | return $this->byHeader[$name];
29 | }
30 |
31 | public function offsetSet($offset, $value): void
32 | {
33 | throw new \RuntimeException('Sorry, column values cannot be modified.');
34 | }
35 |
36 | public function offsetExists($offset): bool
37 | {
38 | return isset($this->byIndex[$offset]) || isset($this->byHeader[$offset]);
39 | }
40 |
41 | public function offsetUnset($offset): void
42 | {
43 | throw new \RuntimeException('Sorry, column values cannot be modified.');
44 | }
45 |
46 | public function offsetGet($offset): mixed
47 | {
48 | if (isset($this->byIndex[$offset])) {
49 | return $this->byIndex[$offset];
50 | }
51 | if (isset($this->byHeader[$offset])) {
52 | return $this->byHeader[$offset];
53 | }
54 |
55 | return null;
56 | }
57 |
58 | public function getIterator(): \Traversable
59 | {
60 | return new \ArrayIterator($this->byHeader);
61 | }
62 |
63 | public function count(): int
64 | {
65 | return count($this->byIndex);
66 | }
67 |
68 | public function toArray(): mixed
69 | {
70 | return $this->byHeader;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/spec/data/holding_response.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 22163771200002204
4 | import
5 | 2015-11-05Z
6 | System
7 | 2018-11-09Z
8 | ILS
9 | h449730-47bibsys_ubo
10 | false
11 |
12 | 00384nx a2200145ui 4500
13 | h449730-47bibsys_ubo
14 | 000631221-47bibsys_ubo
15 | ta
16 | 1511020l||||||||4 uu
17 | kat
18 | 20181109134730.0
19 |
20 | 000631221
21 | (NO-TrBIB)
22 |
23 |
24 | 00kj16342-47bibsys_ubo
25 |
26 |
27 | 1030300
28 | k00041
29 | 839.82
30 | Vol:Ban
31 |
32 |
33 | 00kj16342
34 | 20000529
35 | kat
36 | 303011kj0
37 | 00kj16342
38 | BOOK
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/Bibs/ScanInResponse.php:
--------------------------------------------------------------------------------
1 | data->additional_info;
33 | }
34 |
35 | /**
36 | * Get the scanned-in item.
37 | *
38 | * @return Item
39 | */
40 | public function getItem()
41 | {
42 | $bib = Bib::make($this->client, $this->data->bib_data->mms_id);
43 | $holding = Holding::make($this->client, $bib, $this->data->holding_data->holding_id);
44 |
45 | return Item::make(
46 | $this->client,
47 | $bib,
48 | $holding,
49 | $this->data->item_data->pid
50 | )->init($this->data->item_data);
51 | }
52 |
53 | /**
54 | * Get the Holding object for the scanned-in item.
55 | *
56 | * @return Holding
57 | */
58 | public function getHolding()
59 | {
60 | $bib = Bib::make($this->client, $this->data->bib_data->mms_id);
61 |
62 | return Holding::make(
63 | $this->client,
64 | $bib,
65 | $this->data->holding_data->holding_id
66 | )->init($this->data->holding_data);
67 | }
68 |
69 | /**
70 | * Get the Bib object for the scanned-in item.
71 | *
72 | * @return Bib
73 | */
74 | public function getBib()
75 | {
76 | return Bib::make(
77 | $this->client,
78 | $this->data->bib_data->mms_id
79 | )->init($this->data->bib_data);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/spec/Bibs/ItemsSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, $bib, $holding);
20 | $client->sru = $sru;
21 | }
22 |
23 | public function it_is_initializable(AlmaClient $client)
24 | {
25 | $this->beConstructedWith($client);
26 | $this->shouldHaveType(Items::class);
27 | }
28 |
29 | public function it_returns_a_lazy_loaded_item_object_given_a_barcode(AlmaClient $client)
30 | {
31 | $client->getRedirectLocation('/items', Argument::containing('303011kj0'))
32 | ->shouldBeCalled()
33 | ->willReturn('https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204');
34 |
35 | $item = $this->fromBarcode('303011kj0');
36 | $item->shouldHaveType(Item::class);
37 | }
38 |
39 | public function it_returns_an_item_object_given_a_barcode(AlmaClient $client)
40 | {
41 | $client->getRedirectLocation('/items', Argument::containing('303011kj0'))
42 | ->shouldBeCalled()
43 | ->willReturn('https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204');
44 |
45 | $client->getJSON('/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204')
46 | ->shouldBeCalled()
47 | ->willReturn(SpecHelper::getDummyData('item_response.json'));
48 |
49 | $item = $this->fromBarcode('303011kj0');
50 | $item->shouldHaveType(Item::class);
51 | $item->pid->shouldBe('23163771190002204');
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/spec/Users/UsersSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client);
17 | }
18 |
19 | public function it_is_initializable()
20 | {
21 | $this->shouldHaveType(Users::class);
22 | }
23 |
24 | public function it_provides_lazy_lookup_by_id(AlmaClient $client)
25 | {
26 | $client->getJSON('/users/12345', [])
27 | ->shouldNotBeCalled();
28 |
29 | $user = $this->get('12345');
30 | $user->shouldHaveType(User::class);
31 | }
32 |
33 | public function it_accepts_additional_parameters(AlmaClient $client)
34 | {
35 | $client->getJSON('/users/12345?expand=fees')
36 | ->shouldBeCalled()
37 | ->willReturn(SpecHelper::getDummyData('user_response.json'));
38 |
39 | $this->get('12345', ['expand' => 'fees'])->init();
40 | }
41 |
42 | public function it_provides_lookup_by_id(AlmaClient $client)
43 | {
44 | $client->getJSON('/users/12345')
45 | ->shouldBeCalled()
46 | ->willReturn(SpecHelper::getDummyData('user_response.json'));
47 |
48 | $user = $this->get('12345');
49 |
50 | $user->shouldHaveType(User::class);
51 | $user->primary_id->shouldBe('12345');
52 | $user->primaryId->shouldBe('12345');
53 | }
54 |
55 | public function it_provides_search(AlmaClient $client)
56 | {
57 | $client->getJSON(Argument::containingString('users'), Argument::any())
58 | ->willReturn(SpecHelper::getDummyData('users_response.json'));
59 |
60 | $users = $this->search('last_name~banan');
61 | $first = $users->current();
62 |
63 | $first->shouldHaveType(User::class);
64 | $first->primary_id->shouldBe('1234567');
65 | $first->primaryId->shouldBe('1234567');
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/spec/data/portfolio_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "53182555270002204",
3 | "is_local": false,
4 | "is_standalone": false,
5 | "resource_metadata": {
6 | "mms_id": {
7 | "value": "999919790879802204",
8 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999919790879802204"
9 | },
10 | "title": "Elementary Mechanics Using Matlab A Modern Course Combining Analytical and Numerical Techniques /"
11 | },
12 | "electronic_collection": {
13 | "id": {
14 | "value": "61173723710002204",
15 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/electronic/e-collections/61173723710002204"
16 | },
17 | "service": {
18 | "value": "62173726760002204",
19 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/electronic/e-collections/61173723710002204/e-services/62173726760002204"
20 | }
21 | },
22 | "availability": {
23 | "value": "11",
24 | "desc": "Available"
25 | },
26 | "material_type": {
27 | "value": "BOOK",
28 | "desc": "Book"
29 | },
30 | "library": {
31 | "value": "",
32 | "link": null
33 | },
34 | "linking_details": {
35 | "url": "",
36 | "url_type": {
37 | "value": "",
38 | "desc": null
39 | },
40 | "dynamic_url": "",
41 | "static_url": "",
42 | "parser_parameters": "",
43 | "parser_parameters_override": "",
44 | "proxy_enabled": {
45 | "value": "false",
46 | "desc": "No"
47 | },
48 | "proxy": ""
49 | },
50 | "coverage_details": {
51 | "coverage_in_use": {
52 | "value": "0",
53 | "desc": "Only local"
54 | },
55 | "global_date_coverage_parameters": [],
56 | "local_date_coverage_parameters": []
57 | },
58 | "po_line": {
59 | "value": "",
60 | "link": null
61 | },
62 | "license": {
63 | "value": "070001039",
64 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/acq/licenses/070001039"
65 | },
66 | "pda": {
67 | "value": "",
68 | "link": ""
69 | },
70 | "authentication_note": "",
71 | "public_note": "",
72 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999919790879802204/portfolios/53182555270002204"
73 | }
74 |
--------------------------------------------------------------------------------
/spec/Analytics/RowSpec.php:
--------------------------------------------------------------------------------
1 |
17 | 0
18 | col1 content
19 | col3 content
20 | ');
21 | $xml->registerXPathNamespace('rowset', 'urn:schemas-microsoft-com:xml-analysis:rowset');
22 | $headers = ['mms_id', 'title', 'isbn'];
23 | $this->beConstructedWith($xml, $headers);
24 | }
25 |
26 | public function it_is_initializable()
27 | {
28 | $this->shouldHaveType(Row::class);
29 | }
30 |
31 | public function it_should_have_columns_accessible_by_name()
32 | {
33 | $this->mms_id->shouldBe('col1 content');
34 | $this->title->shouldBe(null);
35 | $this->isbn->shouldBe('col3 content');
36 | }
37 |
38 | public function it_should_have_columns_accessible_by_array_key()
39 | {
40 | $this['mms_id']->shouldBe('col1 content');
41 | $this['title']->shouldBe(null);
42 | $this['isbn']->shouldBe('col3 content');
43 | }
44 |
45 | public function it_should_have_columns_accessible_by_array_index()
46 | {
47 | $this[0]->shouldBe('col1 content');
48 | $this[1]->shouldBe(null);
49 | $this[2]->shouldBe('col3 content');
50 | }
51 |
52 | public function it_should_be_traversable()
53 | {
54 | $this->shouldBeAnInstanceOf('Traversable');
55 | }
56 |
57 | public function it_should_be_countable()
58 | {
59 | $this->shouldHaveCount(3);
60 | }
61 |
62 | public function it_should_be_serializable_as_array()
63 | {
64 | $this->toArray()->shouldBeArray();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Model/SimplePaginatedList.php:
--------------------------------------------------------------------------------
1 | totalRecordCount) && $this->offset >= $this->totalRecordCount) {
24 | return;
25 | }
26 |
27 | $url = $this->url('', [
28 | 'offset' => $this->offset,
29 | 'limit' => $this->limit,
30 | ]);
31 |
32 | $response = $this->client->getJSON($url);
33 |
34 | if (is_null($response)) {
35 | throw new \RuntimeException("Empty response from URL: $url");
36 | }
37 |
38 | return $this->onData($response);
39 | }
40 |
41 | protected function fetchData()
42 | {
43 | do {
44 | $this->fetchBatch();
45 | } while (!$this->isInitialized($this->resources));
46 | }
47 |
48 | protected function onData($data)
49 | {
50 | $before = count($this->resources);
51 | parent::onData($data);
52 | $after = count($this->resources);
53 | $this->offset += $after - $before;
54 | }
55 |
56 | /**
57 | * Check if we have the full representation of our data object.
58 | *
59 | * @param \stdClass $data
60 | *
61 | * @return bool
62 | */
63 | protected function isInitialized($data)
64 | {
65 | if (is_countable($data)) {
66 | return count($data) === $this->totalRecordCount;
67 | }
68 |
69 | return false;
70 | }
71 |
72 | /**
73 | * Total number of resources.
74 | *
75 | * @link http://php.net/manual/en/countable.count.php
76 | *
77 | * @return int
78 | */
79 | public function count()
80 | {
81 | if (is_null($this->totalRecordCount)) {
82 | $this->fetchBatch();
83 | }
84 |
85 | return $this->totalRecordCount;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/spec/data/loans_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "item_loan": [
3 | {
4 | "author": "Polkinghorne, John",
5 | "circ_desk": {
6 | "desc": null,
7 | "value": null
8 | },
9 | "description": null,
10 | "due_date": "2018-08-14T20:00:00Z",
11 | "item_barcode": "025986na0",
12 | "item_policy": {
13 | "description": null,
14 | "value": null
15 | },
16 | "library": {
17 | "desc": "UiO Realfagsbiblioteket",
18 | "value": "1030310"
19 | },
20 | "loan_date": "2013-11-18T07:00:00Z",
21 | "loan_id": "1822301570002204",
22 | "loan_status": "ACTIVE",
23 | "location_code": {
24 | "name": "UREAL Samling 42",
25 | "value": "k00475"
26 | },
27 | "mms_id": "998010107304702204",
28 | "process_status": "RENEW",
29 | "renewable": null,
30 | "title": "The particle play : an account of the ultimate constituents of matter J.C. Polkinghorne",
31 | "user_id": "123435"
32 | },
33 | {
34 | "author": "Vollset, K.",
35 | "call_number": "Ung 839.82 Vol:Ban",
36 | "circ_desk": {
37 | "desc": "Utlånet Ureal",
38 | "value": "DEFAULT_CIRC_DESK"
39 | },
40 | "description": null,
41 | "due_date": "2018-08-20T20:00:00Z",
42 | "item_barcode": "303011kj0",
43 | "item_policy": {
44 | "description": null,
45 | "value": null
46 | },
47 | "library": {
48 | "desc": "UiO HumSam-biblioteket",
49 | "value": "1030300"
50 | },
51 | "loan_date": "2018-07-23T20:25:26.347Z",
52 | "loan_id": "7378239410002204",
53 | "loan_status": "ACTIVE",
54 | "location_code": {
55 | "name": "UHS S-Litt",
56 | "value": "k00040"
57 | },
58 | "mms_id": "990006312214702204",
59 | "process_status": "NORMAL",
60 | "publication_year": "2000",
61 | "renewable": null,
62 | "title": "Bananboken K. Vollset ; [illustrasjoner: Motorfinger og Jim]",
63 | "user_id": "123435"
64 | }
65 | ],
66 | "total_record_count": 2
67 | }
--------------------------------------------------------------------------------
/spec/Bibs/HoldingsSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = 'abc';
17 | $this->beConstructedWith($client, $bib);
18 | }
19 |
20 | public function it_is_initializable()
21 | {
22 | $this->shouldHaveType(Holdings::class);
23 | }
24 |
25 | protected function expectRequest($client)
26 | {
27 | $client->getJSON('/bibs/abc/holdings')
28 | ->shouldBeCalled()
29 | ->willReturn(SpecHelper::getDummyData('holdings_response.json'));
30 | }
31 |
32 | public function it_provides_a_lazy_interface_to_holding_objects(AlmaClient $client, Bib $bib)
33 | {
34 | SpecHelper::expectNoRequests($client);
35 |
36 | $holding_id = '12345'; // str_random();
37 | $holding = $this->get($holding_id);
38 |
39 | $holding->shouldHaveType(Holding::class);
40 | $holding->bib->shouldBe($bib);
41 | $holding->holding_id->shouldBe($holding_id);
42 | }
43 |
44 | public function it_provides_a_lazy_array_interface_to_holding_objects(AlmaClient $client, Bib $bib)
45 | {
46 | SpecHelper::expectNoRequests($client);
47 |
48 | $holding_id = '90123'; // str_random();
49 | $holding = $this[$holding_id];
50 |
51 | $holding->shouldHaveType(Holding::class);
52 | $holding->bib->shouldBe($bib);
53 | $holding->holding_id->shouldBe($holding_id);
54 | }
55 |
56 | public function it_is_countable(AlmaClient $client)
57 | {
58 | $this->expectRequest($client);
59 |
60 | $this->shouldHaveCount(2);
61 | }
62 |
63 | public function it_provides_an_iterator_interface_to_holding_objects(AlmaClient $client)
64 | {
65 | $this->expectRequest($client);
66 |
67 | $this->shouldImplement('Iterator');
68 |
69 | $this->current()->shouldHaveType(Holding::class);
70 | }
71 |
72 | public function it_provides_basic_data_without_loading_the_full_record(AlmaClient $client)
73 | {
74 | $this->expectRequest($client);
75 |
76 | $this->shouldHaveCount(2);
77 | $this->all()[0]->shouldHaveType(Holding::class);
78 | $this->all()[0]->library->desc->shouldBe('BURNS');
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Bibs/Holding.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
31 | $this->holding_id = $holding_id;
32 | $this->items = Items::make($this->client, $bib, $this);
33 | }
34 |
35 | /**
36 | * Get the model data.
37 | */
38 | protected function fetchData()
39 | {
40 | return $this->client->getXML($this->url());
41 | }
42 |
43 | /**
44 | * Check if we have the full representation of our data object.
45 | *
46 | * @param $data
47 | *
48 | * @return bool
49 | */
50 | protected function isInitialized($data)
51 | {
52 | return is_a($data, QuiteSimpleXMLElement::class) && $data->has('record');
53 | }
54 |
55 | /**
56 | * Update the MARC record on this holding object. Chainable method.
57 | *
58 | * @param string $xml
59 | *
60 | * @return Holding
61 | */
62 | public function setMarcRecord($xml)
63 | {
64 | $this->_marc = MarcRecord::fromString($xml);
65 |
66 | return $this;
67 | }
68 |
69 | /**
70 | * Called when data is available to be processed.
71 | *
72 | * @param mixed $data
73 | */
74 | protected function onData($data)
75 | {
76 | $this->setMarcRecord($data->first('record')->asXML());
77 | }
78 |
79 | /**
80 | * Generate the base URL for this resource.
81 | *
82 | * @return string
83 | */
84 | protected function urlBase()
85 | {
86 | return "/bibs/{$this->bib->mms_id}/holdings/{$this->holding_id}";
87 | }
88 |
89 | /**
90 | * Get the MARC record for this holding object.
91 | */
92 | public function getRecord()
93 | {
94 | return $this->init()->_marc;
95 | }
96 |
97 | /**
98 | * Get the items for this holding.
99 | */
100 | public function getItems()
101 | {
102 | return $this->items;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/spec/Users/UserSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, '12345');
18 |
19 | $client->getJSON('/users/12345')
20 | ->willReturn(SpecHelper::getDummyData('user_response.json'));
21 | }
22 |
23 | public function it_is_initializable()
24 | {
25 | $this->shouldHaveType(User::class);
26 | }
27 |
28 | public function it_has_primary_id()
29 | {
30 | $this->primaryId->shouldBe('12345');
31 | }
32 |
33 | public function it_has_barcode()
34 | {
35 | $this->barcode->shouldBe('ub54321');
36 | }
37 |
38 | public function it_has_barcodes()
39 | {
40 | $this->barcodes->shouldBe(['ub54321', 'ntb12897787']);
41 | }
42 |
43 | public function it_has_university_id()
44 | {
45 | $this->universityId->shouldBe('test@uio.no');
46 | }
47 |
48 | public function it_has_university_ids()
49 | {
50 | $this->universityIds->shouldBe(['test@uio.no']);
51 | }
52 |
53 | public function it_has_identifiers()
54 | {
55 | $this->identifiers->all()->shouldBe(['12345', 'ub54321', 'ntb12897787', 'test@uio.no']);
56 | }
57 |
58 | public function it_has_loans(AlmaClient $client)
59 | {
60 | SpecHelper::expectNoRequests($client);
61 | $this->loans->shouldHaveType(Loans::class);
62 | }
63 |
64 | public function it_has_fees(AlmaClient $client)
65 | {
66 | SpecHelper::expectNoRequests($client);
67 | $this->fees->shouldHaveType(Fees::class);
68 | }
69 |
70 | public function it_has_requests()
71 | {
72 | $this->requests->shouldHaveType(Requests::class);
73 | }
74 |
75 | public function it_has_sms()
76 | {
77 | $this->getSmsNumber()->shouldBe('87654321');
78 | }
79 |
80 | public function it_can_change_sms()
81 | {
82 | $this->setSmsNumber('12345678');
83 | $this->getSmsNumber()->shouldBe('12345678');
84 | }
85 |
86 | public function it_can_add_sms()
87 | {
88 | $this->setSmsNumber('9999999');
89 | $this->getSmsNumber()->shouldBe('9999999');
90 | }
91 |
92 | public function it_can_remove_sms()
93 | {
94 | $this->unsetSmsNumber();
95 | $this->getSmsNumber()->shouldBe(null);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/Model/LazyResourceList.php:
--------------------------------------------------------------------------------
1 | responseKey = $responseKey;
36 | }
37 |
38 | /**
39 | * Convert a data element to a resource object.
40 | *
41 | * @param $data
42 | *
43 | * @return mixed
44 | */
45 | abstract protected function convertToResource($data);
46 |
47 | /**
48 | * Called when data is available on the object.
49 | * The resource classes can use this method to process the data.
50 | *
51 | * @param $data
52 | */
53 | protected function onData($data)
54 | {
55 | if (is_null($this->totalRecordCount)) {
56 | $this->totalRecordCount = $data->total_record_count;
57 | }
58 |
59 | if (!isset($data->{$this->responseKey})) {
60 | return;
61 | }
62 |
63 | foreach ($data->{$this->responseKey} as $result) {
64 | $this->resources[] = $this->convertToResource($result);
65 | }
66 | }
67 |
68 | /**
69 | * Check if we have the full representation of our data object.
70 | *
71 | * @param \stdClass $data
72 | *
73 | * @return bool
74 | */
75 | protected function isInitialized($data)
76 | {
77 | return isset($data->total_record_count);
78 | }
79 |
80 | /**
81 | * Get all the resources.
82 | *
83 | * @return array
84 | */
85 | public function all()
86 | {
87 | return $this->init()->resources;
88 | }
89 |
90 | /**
91 | * Number of resources.
92 | *
93 | * @link http://php.net/manual/en/countable.count.php
94 | */
95 | public function count(): int
96 | {
97 | return count($this->all());
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/Model/Model.php:
--------------------------------------------------------------------------------
1 | client = $client;
22 | $this->data = $data;
23 | }
24 |
25 | /**
26 | * @param Client $client
27 | * @param array ...$params
28 | *
29 | * @return static
30 | */
31 | public static function make($client, ...$params)
32 | {
33 | return new static($client, ...$params);
34 | }
35 |
36 | /**
37 | * Load data onto this object. Chainable method.
38 | *
39 | * @param \stdClass|QuiteSimpleXMLElement $data
40 | *
41 | * @return self
42 | */
43 | public function init($data = null)
44 | {
45 | if (!is_null($data)) {
46 | $this->data = $data;
47 | }
48 |
49 | return $this;
50 | }
51 |
52 | /**
53 | * Get the raw data object.
54 | */
55 | public function getData()
56 | {
57 | return $this->data;
58 | }
59 |
60 | /**
61 | * Magic!
62 | *
63 | * @param string $key
64 | *
65 | * @return mixed
66 | */
67 | public function __get($key)
68 | {
69 | // Convert electronic_collections to ElectronicCollections
70 | $key_s = implode('', array_map(function ($x) {
71 | return ucfirst($x);
72 | }, explode('_', $key)));
73 |
74 | // If there's a getter method, call it.
75 | $method = 'get' . ucfirst($key_s);
76 | if (method_exists($this, $method)) {
77 | return $this->$method();
78 | }
79 |
80 | // If the property is already defined on our data object, return it.
81 | if (isset($this->data->{$key})) {
82 | return $this->data->{$key};
83 | }
84 |
85 | $this->init();
86 |
87 | // If data comes from an XML response (Bib or Holding record)
88 | if (is_a($this->data, QuiteSimpleXMLElement::class)) {
89 | return $this->data->text($key);
90 | }
91 |
92 | // If the property is defined on our data object now, return it.
93 | if (isset($this->data->{$key})) {
94 | return $this->data->{$key};
95 | }
96 | }
97 |
98 | public function jsonSerialize(): mixed
99 | {
100 | return $this->data;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/Bibs/Items.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
43 | $this->holding = $holding;
44 | }
45 |
46 | /**
47 | * Convert a data element to a resource object.
48 | *
49 | * @param $data
50 | *
51 | * @return Item
52 | */
53 | protected function convertToResource($data)
54 | {
55 | return Item::make($this->client, $this->bib, $this->holding, $data->item_data->pid)
56 | ->init($data);
57 | }
58 |
59 | /**
60 | * Generate the base URL for this resource.
61 | *
62 | * @return string
63 | */
64 | protected function urlBase()
65 | {
66 | return "/bibs/{$this->bib->mms_id}/holdings/{$this->holding->holding_id}/items";
67 | }
68 |
69 | /**
70 | * Get an Item object from a barcode.
71 | *
72 | * @param string $barcode
73 | *
74 | * @return Item|null
75 | */
76 | public function fromBarcode($barcode)
77 | {
78 | $destinationUrl = $this->client->getRedirectLocation('/items', ['item_barcode' => $barcode]);
79 |
80 | // Extract the MMS ID from the redirect target URL.
81 | // Example: https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999211285764702204/holdings/22156746440002204/items/23156746430002204
82 | if (!is_null($destinationUrl) && preg_match('$bibs/([0-9]+)/holdings/([0-9]+)/items/([0-9]+)$', $destinationUrl, $matches)) {
83 | $mms_id = $matches[1];
84 | $holding_id = $matches[2];
85 | $item_id = $matches[3];
86 |
87 | $bib = Bib::make($this->client, $mms_id);
88 | $holding = Holding::make($this->client, $bib, $holding_id);
89 |
90 | return Item::make($this->client, $bib, $holding, $item_id);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Users/UserIdentifiers.php:
--------------------------------------------------------------------------------
1 | data->primary_id];
22 | foreach ($this->data->user_identifier as $identifier) {
23 | if (is_null($status) || $identifier->status == $status) {
24 | $ids[] = $identifier->value;
25 | }
26 | }
27 |
28 | return $ids;
29 | }
30 |
31 | /**
32 | * Get all active user identifiers of a given type, like 'BARCODE' or 'UNIV_ID'.
33 | *
34 | * @param string $value
35 | * @param string $status
36 | *
37 | * @return array
38 | */
39 | public function allOfType($value, $status = 'ACTIVE')
40 | {
41 | $ids = [];
42 | foreach ($this->data->user_identifier as $identifier) {
43 | if ($identifier->id_type->value == $value && (is_null($status) || $identifier->status == $status)) {
44 | $ids[] = $identifier->value;
45 | }
46 | }
47 |
48 | return $ids;
49 | }
50 |
51 | /**
52 | * Get the first active user identifier of a given type, like 'BARCODE' or 'UNIV_ID'.
53 | *
54 | * @param string $value
55 | * @param string $status
56 | *
57 | * @return null|string
58 | */
59 | public function firstOfType($value, $status = 'ACTIVE')
60 | {
61 | foreach ($this->data->user_identifier as $identifier) {
62 | if ($identifier->id_type->value == $value && (is_null($status) || $identifier->status == $status)) {
63 | return $identifier->value;
64 | }
65 | }
66 | }
67 |
68 | /**
69 | * Get the first active barcode.
70 | *
71 | * @return null|string
72 | */
73 | public function getBarcode()
74 | {
75 | return $this->firstOfType('BARCODE');
76 | }
77 |
78 | /**
79 | * Get all active barcodes.
80 | *
81 | * @return string[]
82 | */
83 | public function getBarcodes()
84 | {
85 | return $this->allOfType('BARCODE');
86 | }
87 |
88 | /**
89 | * Get the first active university id.
90 | *
91 | * @return null|string
92 | */
93 | public function getUniversityId()
94 | {
95 | return $this->firstOfType('UNIV_ID');
96 | }
97 |
98 | /**
99 | * Get all active university ids.
100 | *
101 | * @return string[]
102 | */
103 | public function getUniversityIds()
104 | {
105 | return $this->allOfType('UNIV_ID');
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/spec/data/requested-resources_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "requested_resource": [
3 | {
4 | "location": {
5 | "call_number": "2011 TAN",
6 | "copy": [
7 | {
8 | "alternative_call_number": "",
9 | "barcode": "049313na0",
10 | "base_status": {
11 | "desc": "Item in place",
12 | "value": "1"
13 | },
14 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/991120800814702204/holdings/22166970490002204/items/23166970440002204",
15 | "pid": "23166970440002204",
16 | "storage_location_id": ""
17 | }
18 | ],
19 | "holding_id": {
20 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/991120800814702204/holdings/22166970490002204",
21 | "value": "22166970490002204"
22 | },
23 | "library": {
24 | "desc": "UiO Realfagsbiblioteket",
25 | "value": "1030310"
26 | },
27 | "shelving_location": "k00464"
28 | },
29 | "request": [
30 | {
31 | "destination": {
32 | "desc": "UiO Realfagsbiblioteket",
33 | "value": "1030310"
34 | },
35 | "id": "7989649590002204",
36 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/991120800814702204/requests/7989344220002204",
37 | "printed": false,
38 | "reported": false,
39 | "request_date": "2018-10-10Z",
40 | "request_sub_type": {
41 | "desc": "Patron physical item request",
42 | "value": "PATRON_PHYSICAL"
43 | },
44 | "request_type": "HOLD",
45 | "requester": {
46 | "desc": "Test User",
47 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/users/test-user",
48 | "value": null
49 | }
50 | }
51 | ],
52 | "resource_metadata": {
53 | "author": "Tanveer, Omar",
54 | "isbn": null,
55 | "issn": null,
56 | "mms_id": {
57 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/991120800814702204",
58 | "value": "991120800814702204"
59 | },
60 | "publication_place": "Oslo",
61 | "publication_year": "2011",
62 | "publisher": "O Tanveer",
63 | "title": "Complexity assessment within IT portfolios Omar Tanveer"
64 | }
65 | }
66 | ],
67 | "total_record_count": 1
68 | }
69 |
--------------------------------------------------------------------------------
/spec/Analytics/ReportSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($almaClient, '/test/path');
17 | }
18 |
19 | public function it_is_initializable()
20 | {
21 | $this->shouldHaveType(Report::class);
22 | }
23 |
24 | public function it_supports_setting_headers(Client $almaClient)
25 | {
26 | $this->beConstructedWith($almaClient, '/test/path', ['a', 'b']);
27 |
28 | $this->headers->shouldBe(['a', 'b']);
29 | }
30 |
31 | public function it_supports_setting_filter(Client $almaClient)
32 | {
33 | $this->beConstructedWith($almaClient, '/test/path', ['a', 'b'], 'la la la');
34 |
35 | $this->filter->shouldBe('la la la');
36 | }
37 |
38 | public function it_parses_column_headers(Client $almaClient)
39 | {
40 | $almaClient->getXML('/analytics/reports?path=%2Ftest%2Fpath&limit=1000')
41 | ->shouldBeCalledTimes(1)
42 | ->willReturn(SpecHelper::getDummyData('analytics_response.xml'));
43 |
44 | // $this->getHeaders()->shouldHaveCount(11);
45 | $this->getHeaders()->shouldContain('Event Start Date and Time');
46 |
47 | $firstRow = $this->current();
48 | $firstRow->shouldHaveType(Row::class);
49 | $firstRow['Event Start Date and Time']->shouldBe('2017-08-29T15:43:53');
50 | }
51 |
52 | public function it_supports_resumption(Client $almaClient)
53 | {
54 | $path = '/test/path';
55 |
56 | // To speed up tests
57 | Report::$retryDelayTime = 0;
58 |
59 | $almaClient->getXML('/analytics/reports?path=%2Ftest%2Fpath&limit=1000')
60 | ->shouldBeCalledTimes(1)
61 | ->willReturn(SpecHelper::getDummyData('analytics_response_part1.xml'));
62 |
63 | $almaClient->getXML('/analytics/reports?limit=1000&token=9672D715A8E2EAAA6F30DD22FC52BE4CCAE35E29D921E0AC8BE8C6734C9E1571B4E48EEFCA4046EFF8CD7D1662C2D0A7677D3AD05EDC3CA7F06182E34E9D7A2F')
64 | ->shouldBeCalledTimes(3)
65 | ->willReturn(
66 |
67 | // If Analytics is having a bad day, we might get a "still loading" response
68 | // See: https://bitbucket.org/uwlib/uwlib-alma-analytic-tools/wiki/Understanding_Analytic_GET_Requests#!analytic-still-loading
69 | SpecHelper::getDummyData('analytics_still_loading_response.xml'),
70 | SpecHelper::getDummyData('analytics_response_part2.xml'),
71 | SpecHelper::getDummyData('analytics_response_part3.xml')
72 | );
73 |
74 | $this->shouldHaveCount(150 + 150 + 88);
75 | }
76 |
77 | public function it_might_not_exist(Client $almaClient)
78 | {
79 | $almaClient->getXML('/analytics/reports?path=%2Ftest%2Fpath&limit=1000')
80 | ->shouldBeCalledTimes(1)
81 | ->willThrow(new ResourceNotFound('Path not found (/test/path)'));
82 |
83 | $this->exists()->shouldReturn(false);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/spec/Bibs/BibSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client, '999104760474702204');
21 | }
22 |
23 | protected function expectRequest($client)
24 | {
25 | $client->getXML('/bibs/999104760474702204')
26 | ->shouldBeCalled()
27 | ->willReturn(SpecHelper::getDummyData('bib_response_iz.xml'));
28 | }
29 |
30 | public function it_is_lazy(AlmaClient $client)
31 | {
32 | SpecHelper::expectNoRequests($client);
33 | $this->shouldHaveType(Bib::class);
34 | }
35 |
36 | public function it_fetches_record_data_when_needed(AlmaClient $client)
37 | {
38 | $this->expectRequest($client);
39 |
40 | $this->created_by->shouldBe('import');
41 | $this->created_date->shouldBe('2015-11-05Z');
42 | }
43 |
44 | public function it_can_exist(AlmaClient $client)
45 | {
46 | $this->expectRequest($client);
47 |
48 | $this->exists()->shouldBe(true);
49 | }
50 |
51 | public function it_links_to_network_zone(AlmaClient $client, AlmaClient $nz, Bibs $bibs, Bib $nz_bib)
52 | {
53 | $this->expectRequest($client);
54 |
55 | $client->nz = $nz;
56 | $nz->bibs = $bibs;
57 | $bibs->get('999104760474702201')
58 | ->shouldBeCalled()
59 | ->willReturn($nz_bib);
60 |
61 | $this->getNzRecord()->shouldHaveType(Bib::class);
62 | }
63 |
64 | public function it_provides_lazy_access_to_holdings(AlmaClient $client)
65 | {
66 | SpecHelper::expectNoRequests($client);
67 | $this->holdings->shouldHaveType(Holdings::class);
68 | }
69 |
70 | public function it_has_a_MARC_record(AlmaClient $client)
71 | {
72 | $this->expectRequest($client);
73 |
74 | $this->record->shouldHaveType(Record::class);
75 | $this->record->getField('245')->getSubfield('a')->getData()->shouldBe('Lonely hearts of the cosmos :');
76 | }
77 |
78 | public function it_can_be_edited(AlmaClient $client)
79 | {
80 | $this->expectRequest($client);
81 |
82 | $this->record->getField('245')->getSubfield('a')->setData('New title');
83 |
84 | $client->putXML('/bibs/999104760474702204', Argument::containingString('New title'))
85 | ->shouldBeCalled();
86 |
87 | $this->save();
88 | }
89 |
90 | public function it_catches_resource_not_found(AlmaClient $client)
91 | {
92 | $client->getXML('/bibs/999104760474702204')
93 | ->shouldBeCalled()
94 | ->willThrow(ResourceNotFound::class);
95 |
96 | $this->exists()->shouldBe(false);
97 | }
98 |
99 | public function it_has_requests()
100 | {
101 | $this->requests->shouldHaveType(Requests::class);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/Laravel/ServiceProvider.php:
--------------------------------------------------------------------------------
1 | publishes([
29 | __DIR__ . '/../../config/alma.php' => config_path('alma.php'),
30 | ]);
31 | }
32 |
33 | /**
34 | * Register the service provider.
35 | *
36 | * @return void
37 | */
38 | public function register()
39 | {
40 | $this->mergeConfigFrom(
41 | __DIR__ . '/../../config/alma.php',
42 | 'alma'
43 | );
44 |
45 | $this->app->singleton(AlmaClient::class, function ($app) {
46 |
47 | // Create Alma client
48 | $alma = new AlmaClient(
49 | $app['config']->get('alma.iz.key'),
50 | $app['config']->get('alma.region'),
51 | Zones::INSTITUTION,
52 | isset($app[HttpClientInterface::class]) ? $app[HttpClientInterface::class] : null,
53 | isset($app[RequestFactoryInterface::class]) ? $app[RequestFactoryInterface::class] : null,
54 | isset($app[UriFactoryInterface::class]) ? $app[UriFactoryInterface::class] : null
55 | );
56 |
57 | if ($app['config']->get('alma.iz.entrypoint')) {
58 | $alma->setEntryPoint($app['config']->get('alma.iz.entrypoint'));
59 | }
60 | $alma->setExtraHeaders($app['config']->get('alma.iz.headers', []));
61 |
62 | // Set network zone key, if any
63 | $alma->nz->setKey($app['config']->get('alma.nz.key'));
64 |
65 | if ($app['config']->get('alma.nz.entrypoint')) {
66 | $alma->nz->setEntryPoint($app['config']->get('alma.nz.entrypoint'));
67 | }
68 | $alma->nz->setExtraHeaders($app['config']->get('alma.nz.headers', []));
69 |
70 | // Optionally, attach SRU client for institution zone
71 | if ($app['config']->get('alma.iz.sru')) {
72 | $alma->setSruClient(new SruClient(
73 | $app['config']->get('alma.iz.sru'),
74 | ['version' => '1.2', 'schema' => 'marcxml']
75 | ));
76 | }
77 |
78 | // Optionally, attach SRU client for network zone
79 | if ($app['config']->get('alma.nz.sru')) {
80 | $alma->nz->setSruClient(new SruClient(
81 | $app['config']->get('alma.nz.sru'),
82 | ['version' => '1.2', 'schema' => 'marcxml']
83 | ));
84 | }
85 |
86 | return $alma;
87 | });
88 | }
89 |
90 | /**
91 | * Get the services provided by the provider.
92 | *
93 | * @return array
94 | */
95 | public function provides()
96 | {
97 | return [AlmaClient::class];
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/Bibs/Bibs.php:
--------------------------------------------------------------------------------
1 | client = $client;
20 | }
21 |
22 | /**
23 | * Get a Bib object.
24 | *
25 | * @param string $mms_id
26 | * @param array $expand Expand the bibliographic record with additional information.
27 | *
28 | * @return Bib
29 | */
30 | public function get($mms_id, $expand = null)
31 | {
32 | $params = ['expand' => $expand];
33 |
34 | return Bib::make($this->client, $mms_id)
35 | ->setParams($params);
36 | }
37 |
38 | /**
39 | * Get a Bib object from a item barcode.
40 | *
41 | * @param string $barcode
42 | *
43 | * @return Bib
44 | */
45 | public function fromBarcode($barcode)
46 | {
47 | $destinationUrl = $this->client->getRedirectLocation('/items', ['item_barcode' => $barcode]);
48 |
49 | // Extract the MMS ID from the redirect target URL.
50 | // Example: https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/999211285764702204/holdings/22156746440002204/items/23156746430002204
51 | if (!is_null($destinationUrl) && preg_match('$bibs/([0-9]+)/holdings/([0-9]+)/items/([0-9]+)$', $destinationUrl, $matches)) {
52 | $mmsId = $matches[1];
53 |
54 | return $this->get($mmsId);
55 | }
56 | }
57 |
58 | /**
59 | * Get a Bib object from a holdings ID.
60 | *
61 | * @param string $holdings_id
62 | *
63 | * @return Bib
64 | */
65 | public function fromHoldingsId($holdings_id)
66 | {
67 | $data = $this->client->getXML('/bibs', ['holdings_id' => $holdings_id]);
68 |
69 | return $this->get($data->text('bib/mms_id'))
70 | ->init($data->first('bib'));
71 | }
72 |
73 | /**
74 | * Get Bib records from SRU search. You must have an SRU client connected
75 | * to the Alma client (see `Client::setSruClient()`).
76 | * Returns a generator that handles continuation under the hood.
77 | *
78 | * @param string $cql The CQL query
79 | * @param int $batchSize Number of records to return in each batch.
80 | *
81 | * @return \Generator|Bib[]
82 | */
83 | public function search($cql, $batchSize = 10)
84 | {
85 | $this->client->assertHasSruClient();
86 |
87 | foreach ($this->client->sru->all($cql, $batchSize) as $sruRecord) {
88 | yield Bib::fromSruRecord($sruRecord, $this->client);
89 | }
90 | }
91 |
92 | /**
93 | * Returns the first result from a SRU search or null if no results.
94 | *
95 | * @param string $cql
96 | *
97 | * @return Bib
98 | */
99 | public function findOne($cql)
100 | {
101 | return $this->search($cql, 1)->current();
102 | }
103 |
104 | /**
105 | * Get a Bib object from an ISBN value. Returns null if no Bib record found.
106 | *
107 | * @param string $isbn
108 | *
109 | * @return Bib
110 | */
111 | public function fromIsbn($isbn)
112 | {
113 | return $this->findOne('alma.isbn="' . $isbn . '"');
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/spec/Bibs/BibsSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($client);
19 | $client->sru = $sru;
20 | }
21 |
22 | public function it_provides_a_lazy_interface_to_bib_objects(AlmaClient $client)
23 | {
24 | SpecHelper::expectNoRequests($client);
25 |
26 | $mms_id = '123'; // str_random();
27 | $bib = $this->get($mms_id);
28 |
29 | $bib->shouldHaveType(Bib::class);
30 | $bib->mms_id->shouldBe($mms_id);
31 | }
32 |
33 | public function it_provides_a_lazy_array_interface_to_bib_objects(AlmaClient $client)
34 | {
35 | SpecHelper::expectNoRequests($client);
36 |
37 | $mms_id = '123'; // str_random();
38 | $bib = $this[$mms_id];
39 |
40 | $bib->shouldHaveType(Bib::class);
41 | $bib->mms_id->shouldBe($mms_id);
42 | }
43 |
44 | public function it_accepts_expand_parameter(AlmaClient $client)
45 | {
46 | $client->getXML('/bibs/12345?expand=p_avail')
47 | ->shouldBeCalled()
48 | ->willReturn(SpecHelper::getDummyData('bib_response_with_availability.xml'));
49 |
50 | $this->get('12345', 'p_avail')->record;
51 | }
52 |
53 | public function it_provides_lookup_by_isbn(AlmaClient $client, SruClient $sru)
54 | {
55 | SpecHelper::expectNoRequests($client);
56 | $client->assertHasSruClient()->shouldBeCalled()->willReturn(true);
57 |
58 | $sru->all('alma.isbn="123"', 1)
59 | ->shouldBeCalled()
60 | ->willReturn([SruRecord::make(
61 | 1,
62 | '990114012304702201'
63 | )]);
64 |
65 | $bib = $this->fromIsbn('123');
66 | $bib->shouldHaveType(Bib::class);
67 |
68 | // This operation should be lazy
69 | $bib->mms_id->shouldBe('990114012304702201');
70 |
71 | // This operation should also be lazy
72 | $bib->record->shouldBeAnInstanceOf(Record::class);
73 | }
74 |
75 | public function it_returns_null_given_unknown_isbn(AlmaClient $client, SruClient $sru)
76 | {
77 | SpecHelper::expectNoRequests($client);
78 | $client->assertHasSruClient()->shouldBeCalled()->willReturn(true);
79 |
80 | $sru->all('alma.isbn="123"', 1)
81 | ->shouldBeCalled()
82 | ->willReturn([]);
83 |
84 | $bib = $this->fromIsbn('123');
85 | $bib->shouldBe(null);
86 | }
87 |
88 | public function it_supports_lookup_by_holding_id(AlmaClient $client)
89 | {
90 | $client->getXML('/bibs', Argument::containing('12345'))
91 | ->shouldBeCalled()
92 | ->willReturn(SpecHelper::getDummyData('bibs_holdings.xml'));
93 |
94 | $bib = $this->fromHoldingsId('12345');
95 | $bib->shouldHaveType(Bib::class);
96 | $bib->mms_id->shouldBe('999900137074702204');
97 | }
98 |
99 | /*
100 | public function it_returns_a_bib_object_given_a_barcode(AlmaClient $client)
101 | {
102 | }
103 | */
104 | }
105 |
--------------------------------------------------------------------------------
/spec/Bibs/ItemSpec.php:
--------------------------------------------------------------------------------
1 | mms_id = '990006312214702204';
22 | $holding->holding_id = '22163771200002204';
23 | $item_id = '23163771190002204';
24 |
25 | $this->beConstructedWith($client, $bib, $holding, $item_id);
26 | }
27 |
28 | public function it_is_initializable()
29 | {
30 | $this->shouldHaveType(Item::class);
31 | }
32 |
33 | public function it_can_be_checked_out(AlmaClient $client, User $user, Library $library)
34 | {
35 | $client->postJSON(
36 | '/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204/loans?user_id=Dan+Michael',
37 | [
38 | 'library' => ['value' => 'THAT LIBRARY'],
39 | 'circ_desk' => ['value' => 'DEFAULT_CIRC_DESK'],
40 | ]
41 | )
42 | ->shouldBeCalled()
43 | ->willReturn(SpecHelper::getDummyData('create_loan_response.json'));
44 |
45 | $user->id = 'Dan Michael';
46 | $library->code = 'THAT LIBRARY';
47 |
48 | $this->checkOut($user, $library)
49 | ->shouldHaveType(Loan::class);
50 | }
51 |
52 | public function it_can_be_on_loan(AlmaClient $client, User $user, Library $library)
53 | {
54 | $client->getJSON('/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204/loans')
55 | ->shouldBeCalled()
56 | ->willReturn(SpecHelper::getDummyData('item_loan_response.json'));
57 |
58 | $this->getLoan()->shouldHaveType(Loan::class);
59 | $this->loan->shouldHaveType(Loan::class);
60 | }
61 |
62 | public function it_can_be_available(AlmaClient $client, User $user, Library $library)
63 | {
64 | $client->getJSON('/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204/loans')
65 | ->shouldBeCalled()
66 | ->willReturn(SpecHelper::getDummyData('item_no_loan_response.json'));
67 |
68 | $this->getLoan()->shouldBe(null);
69 | $this->loan->shouldBe(null);
70 | }
71 |
72 | public function it_can_be_scanned_in(AlmaClient $client, Library $library)
73 | {
74 | $client->postJSON('/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204?op=scan&library=THAT+LIBRARY&circ_desk=DEFAULT_CIRC_DESK')
75 | ->shouldBeCalled()
76 | ->willReturn(SpecHelper::getDummyData('scanin_transit_response.json'));
77 |
78 | $library->code = 'THAT LIBRARY';
79 |
80 | $this->scanIn($library)
81 | ->shouldHaveType(ScanInResponse::class);
82 | }
83 |
84 | public function it_can_be_scanned_in_with_params(AlmaClient $client, Library $library)
85 | {
86 | $client->postJSON('/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204?place_on_hold_shelf=true&op=scan&library=THAT+LIBRARY&circ_desk=OTHER_DESK')
87 | ->shouldBeCalled()
88 | ->willReturn(SpecHelper::getDummyData('scanin_transit_response.json'));
89 |
90 | $library->code = 'THAT LIBRARY';
91 |
92 | $this->scanIn($library, 'OTHER_DESK', ['place_on_hold_shelf' => 'true'])
93 | ->shouldHaveType(ScanInResponse::class);
94 | }
95 |
96 | public function it_has_requests()
97 | {
98 | $this->requests->shouldHaveType(Requests::class);
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/Model/LazyResource.php:
--------------------------------------------------------------------------------
1 | params = $params;
38 |
39 | return $this;
40 | }
41 |
42 | /**
43 | * Get the request query string parameters.
44 | *
45 | * @return array
46 | */
47 | public function getParams()
48 | {
49 | return $this->params;
50 | }
51 |
52 | /**
53 | * Check if we have the full representation of our data object.
54 | *
55 | * @param \stdClass $data
56 | *
57 | * @return bool
58 | */
59 | abstract protected function isInitialized($data);
60 |
61 | /**
62 | * Load data onto this object. Chainable method.
63 | *
64 | * @param \stdClass|QuiteSimpleXMLElement $data
65 | *
66 | * @return $this
67 | */
68 | public function init($data = null)
69 | {
70 | if ($this->initialized) {
71 | return $this;
72 | }
73 |
74 | if (is_null($data)) {
75 | $data = $this->fetchData();
76 | }
77 |
78 | if ($this->isInitialized($data)) {
79 | $this->initialized = true;
80 | }
81 |
82 | $this->data = $data;
83 | if ($this->initialized) {
84 | $this->onData($data);
85 | }
86 |
87 | return $this;
88 | }
89 |
90 | /**
91 | * Get and return the model data.
92 | *
93 | * @return object
94 | */
95 | protected function fetchData()
96 | {
97 | return $this->client->getJSON($this->url());
98 | }
99 |
100 | /**
101 | * Called when data is available on the object.
102 | * The resource classes can use this method to process the data.
103 | *
104 | * @param mixed $data
105 | */
106 | protected function onData($data)
107 | {
108 | }
109 |
110 | /**
111 | * Get the raw data object.
112 | */
113 | public function getData()
114 | {
115 | return $this->init()->data;
116 | }
117 |
118 | /**
119 | * Check if the object exists.
120 | */
121 | public function exists()
122 | {
123 | try {
124 | $this->init();
125 | } catch (ResourceNotFound $ex) {
126 | }
127 |
128 | return $this->initialized;
129 | }
130 |
131 | /**
132 | * Generate the base URL for this resource.
133 | *
134 | * @return string
135 | */
136 | abstract protected function urlBase();
137 |
138 | /**
139 | * Build a relative URL for a resource.
140 | *
141 | * @param string $path
142 | * @param array $query
143 | *
144 | * @return string
145 | */
146 | protected function url($path = '', $query = [])
147 | {
148 | $path = $this->urlBase() . $path;
149 | $query = http_build_query(array_merge($this->params, $query));
150 |
151 | $url = $path;
152 | if (!empty($query)) {
153 | $url .= '?' . $query;
154 | }
155 |
156 | return $url;
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/spec/data/bib_response_nz.xml:
--------------------------------------------------------------------------------
1 | 999104760474702201marc21Lonely hearts of the cosmos : the scientific quest for the secret of the universeOverbye, Dennis0060159642(NO-TrBIB)910476047910476047-47bibsys_networkNew YorkHarper Collinsimport2015-11-02ZSystem2016-06-20ZfalseILS910476047-47bibsys_network01136cam a2200349 c 450099910476047470220120160620201908.0ta150121s1991 xx#|||||||||||000|0|eng|d0060159642ib.910476047-47bibsys_network(NO-TrBIB)910476047NO-TrBIBnobkatreg524.8(092)523.1NO-OsNB4/norFa:7utkOverbye, Dennis(NO-TrBIB)90545755Lonely hearts of the cosmos :the scientific quest for the secret of the universeDennis OverbyeNew YorkHarper Collinsc1991VIII, 438 s., pl.ill.Sandage, Allan(NO-TrBIB)90061406CosmologyAstronomersBiographyKosmologinoubomnUniversetnoubomnKosmologiBiografitekordUniversets opprinnelsetekorduniversetkosmologihistoriebiografierpopulærvitenskapBiografiernoubomnPopulærvitenskapnoubomnHistorienoubomn80
2 |
--------------------------------------------------------------------------------
/spec/data/item_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "bib_data": {
3 | "author": "Vollset, K.",
4 | "complete_edition": "",
5 | "date_of_publication": "2000",
6 | "isbn": "8247806290",
7 | "issn": null,
8 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/990006312214702204",
9 | "mms_id": "990006312214702204",
10 | "network_number": [
11 | "(NO-TrBIB)092093302",
12 | "(NO-TrBIB)000631221",
13 | "000631221-47bibsys_network",
14 | "(EXLNZ-47BIBSYS_NETWORK)990006312214702201"
15 | ],
16 | "place_of_publication": "[Oslo]",
17 | "publisher_const": "Gyldendal Tiden",
18 | "title": "Bananboken"
19 | },
20 | "holding_data": {
21 | "accession_number": "",
22 | "call_number": "Ung 839.82 Vol:Ban",
23 | "call_number_type": {
24 | "desc": "Other scheme",
25 | "value": "8"
26 | },
27 | "copy_id": "",
28 | "holding_id": "22163771200002204",
29 | "in_temp_location": false,
30 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/990006312214702204/holdings/22163771200002204",
31 | "temp_call_number": "",
32 | "temp_call_number_type": {
33 | "desc": null,
34 | "value": ""
35 | },
36 | "temp_library": {
37 | "desc": null,
38 | "value": null
39 | },
40 | "temp_location": {
41 | "desc": null,
42 | "value": null
43 | },
44 | "temp_policy": {
45 | "desc": null,
46 | "value": ""
47 | }
48 | },
49 | "item_data": {
50 | "alternative_call_number": "",
51 | "alternative_call_number_type": {
52 | "desc": null,
53 | "value": ""
54 | },
55 | "arrival_date": "2000-05-29Z",
56 | "barcode": "303011kj0",
57 | "base_status": {
58 | "desc": "Item in place",
59 | "value": "1"
60 | },
61 | "chronology_i": "",
62 | "chronology_j": "",
63 | "chronology_k": "",
64 | "chronology_l": "",
65 | "chronology_m": "",
66 | "creation_date": "2015-11-05Z",
67 | "description": "",
68 | "edition": null,
69 | "enumeration_a": "",
70 | "enumeration_b": "",
71 | "enumeration_c": "",
72 | "enumeration_d": "",
73 | "enumeration_e": "",
74 | "enumeration_f": "",
75 | "enumeration_g": "",
76 | "enumeration_h": "",
77 | "fulfillment_note": "",
78 | "imprint": null,
79 | "internal_note_1": "Status: kat - kat",
80 | "internal_note_2": "TIME FOR CIRC STATUS: 2015-11-02 | CIRC STATUS: 0",
81 | "internal_note_3": "",
82 | "inventory_number": "00kj16342",
83 | "is_magnetic": false,
84 | "language": null,
85 | "library": {
86 | "desc": "UiO HumSam-biblioteket",
87 | "value": "1030300"
88 | },
89 | "location": {
90 | "desc": "UHS S-Litt",
91 | "value": "k00040"
92 | },
93 | "modification_date": "2015-11-24Z",
94 | "pages": "",
95 | "physical_condition": {
96 | "desc": null,
97 | "value": null
98 | },
99 | "physical_material_type": {
100 | "desc": "Book",
101 | "value": "BOOK"
102 | },
103 | "pid": "23163771190002204",
104 | "pieces": "",
105 | "po_line": "",
106 | "policy": {
107 | "desc": null,
108 | "value": ""
109 | },
110 | "process_type": {
111 | "desc": null,
112 | "value": ""
113 | },
114 | "provenance": {
115 | "desc": null,
116 | "value": ""
117 | },
118 | "public_note": "",
119 | "receiving_operator": "import",
120 | "requested": false,
121 | "statistics_note_1": "",
122 | "statistics_note_2": "",
123 | "statistics_note_3": "",
124 | "storage_location_id": "",
125 | "year_of_issue": ""
126 | },
127 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204"
128 | }
--------------------------------------------------------------------------------
/spec/data/scanin_transit_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "additional_info": "Item's destination is: UiO HumSam-biblioteket. Request/Process Type: Transit for reshelving. Requester: . Requester ID: . Place in Queue: 1",
3 | "bib_data": {
4 | "author": "Vollset, K.",
5 | "complete_edition": "",
6 | "date_of_publication": "2000",
7 | "isbn": "8247806290",
8 | "issn": null,
9 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/990006312214702204",
10 | "mms_id": "990006312214702204",
11 | "network_number": [
12 | "(NO-TrBIB)092093302",
13 | "(NO-TrBIB)000631221",
14 | "000631221-47bibsys_network",
15 | "(EXLNZ-47BIBSYS_NETWORK)990006312214702201"
16 | ],
17 | "place_of_publication": "[Oslo]",
18 | "publisher_const": "Gyldendal Tiden",
19 | "title": "Bananboken"
20 | },
21 | "holding_data": {
22 | "accession_number": "",
23 | "call_number": "Ung 839.82 Vol:Ban",
24 | "call_number_type": {
25 | "desc": "Other scheme",
26 | "value": "8"
27 | },
28 | "copy_id": "",
29 | "holding_id": "22163771200002204",
30 | "in_temp_location": false,
31 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/990006312214702204/holdings/22163771200002204",
32 | "temp_call_number": "",
33 | "temp_call_number_type": {
34 | "desc": null,
35 | "value": ""
36 | },
37 | "temp_library": {
38 | "desc": null,
39 | "value": null
40 | },
41 | "temp_location": {
42 | "desc": null,
43 | "value": null
44 | },
45 | "temp_policy": {
46 | "desc": null,
47 | "value": ""
48 | }
49 | },
50 | "item_data": {
51 | "alternative_call_number": "",
52 | "alternative_call_number_type": {
53 | "desc": null,
54 | "value": ""
55 | },
56 | "arrival_date": "2000-05-29Z",
57 | "barcode": "303011kj0",
58 | "base_status": {
59 | "desc": "Item not in place",
60 | "value": "0"
61 | },
62 | "chronology_i": "",
63 | "chronology_j": "",
64 | "chronology_k": "",
65 | "chronology_l": "",
66 | "chronology_m": "",
67 | "creation_date": "2015-11-05Z",
68 | "description": "",
69 | "edition": null,
70 | "enumeration_a": "",
71 | "enumeration_b": "",
72 | "enumeration_c": "",
73 | "enumeration_d": "",
74 | "enumeration_e": "",
75 | "enumeration_f": "",
76 | "enumeration_g": "",
77 | "enumeration_h": "",
78 | "fulfillment_note": "",
79 | "imprint": null,
80 | "internal_note_1": "Status: kat - kat",
81 | "internal_note_2": "TIME FOR CIRC STATUS: 2015-11-02 | CIRC STATUS: 0",
82 | "internal_note_3": "",
83 | "inventory_number": "00kj16342",
84 | "is_magnetic": false,
85 | "language": null,
86 | "library": {
87 | "desc": "UiO HumSam-biblioteket",
88 | "value": "1030300"
89 | },
90 | "location": {
91 | "desc": "UHS S-Litt",
92 | "value": "k00040"
93 | },
94 | "modification_date": "2018-07-15Z",
95 | "pages": "",
96 | "physical_condition": {
97 | "desc": null,
98 | "value": null
99 | },
100 | "physical_material_type": {
101 | "desc": "Book",
102 | "value": "BOOK"
103 | },
104 | "pid": "23163771190002204",
105 | "pieces": "",
106 | "po_line": "",
107 | "policy": {
108 | "desc": null,
109 | "value": ""
110 | },
111 | "process_type": {
112 | "desc": "Transit",
113 | "value": "TRANSIT"
114 | },
115 | "provenance": {
116 | "desc": null,
117 | "value": ""
118 | },
119 | "public_note": "",
120 | "receiving_operator": "import",
121 | "requested": null,
122 | "statistics_note_1": "",
123 | "statistics_note_2": "",
124 | "statistics_note_3": "",
125 | "storage_location_id": "",
126 | "year_of_issue": ""
127 | },
128 | "link": "https://api-eu.hosted.exlibrisgroup.com/almaws/v1/bibs/990006312214702204/holdings/22163771200002204/items/23163771190002204"
129 | }
--------------------------------------------------------------------------------
/spec/data/bib_response_iz.xml:
--------------------------------------------------------------------------------
1 | 999104760474702204marc21999104760474702201Lonely hearts of the cosmos : the scientific quest for the secret of the universeOverbye, Dennis0060159642(NO-TrBIB)910476047910476047-47bibsys_network(EXLNZ-47BIBSYS_NETWORK)999104760474702201New Yorkc1991Harper Collinsimport2015-11-05Zsystem2018-07-05ZfalseILS910476047-47bibsys_network8001186cam a2200349 c 450099910476047470220420171207121755.0ta150121s1991 xx#|||||||||||000|0|eng|d0060159642ib.910476047-47bibsys_network(NO-TrBIB)910476047(EXLNZ-47BIBSYS_NETWORK)999104760474702201NO-TrBIBnobkatreg524.8(092)523.1NO-OsNB4/norFa:7utkfa1351LOCALOverbye, Dennis(NO-TrBIB)90545755Lonely hearts of the cosmos :the scientific quest for the secret of the universeDennis OverbyeNew YorkHarper Collinsc1991VIII, 438 s., pl.ill.Sandage, Allan(NO-TrBIB)90061406bareCosmologyAstronomersBiographyKosmologinoubomn(NO-TrBIB)REAL013436Universetnoubomn(NO-TrBIB)REAL013999KosmologiBiografitekordUniversets opprinnelsetekorduniversetkosmologihistoriebiografierpopulærvitenskapBiografiernoubomnPopulærvitenskapnoubomnHistorienoubomn80
--------------------------------------------------------------------------------
/src/Users/Users.php:
--------------------------------------------------------------------------------
1 | client = $client;
22 | }
23 |
24 | /**
25 | * Get a User object by id.
26 | *
27 | * @param $user_id int
28 | * @param $params array Additional query string parameters
29 | *
30 | * @return User
31 | */
32 | public function get($user_id, $params = [])
33 | {
34 | return User::make($this->client, $user_id)
35 | ->setParams($params);
36 | }
37 |
38 | /**
39 | * Get the first user matching a given query, or NULL if not found.
40 | *
41 | * @param string $query
42 | * @param array $options
43 | *
44 | * @return User|null
45 | */
46 | public function findOne($query, array $options = [])
47 | {
48 | return $this->search($query, $options)->current();
49 | }
50 |
51 | /**
52 | * Iterates over all users matching the given query.
53 | * Handles continuation.
54 | *
55 | * @param string $query
56 | * @param array $options
57 | *
58 | * @return \Generator
59 | */
60 | public function search($query, array $options = [])
61 | {
62 | // Max number of records to fetch. Set to 0 to fetch all.
63 | $limit = array_key_exists('limit', $options) ? $options['limit'] : 0;
64 |
65 | // Set to true to do a phrase search
66 | $phrase = array_key_exists('phrase', $options) ? $options['phrase'] : false;
67 |
68 | // Set to true to expand all query results to full records.
69 | // Please note that this will make queries significantly slower!
70 | $expand = array_key_exists('expand', $options) ? $options['expand'] : false;
71 |
72 | // Number of records to fetch each batch. Usually no need to change this.
73 | $batchSize = array_key_exists('batchSize', $options) ? $options['batchSize'] : 10;
74 |
75 | if ($limit != 0 && $limit < $batchSize) {
76 | $batchSize = $limit;
77 | }
78 |
79 | // The API will throw a 400 response if you include properly encoded spaces,
80 | // but underscores work as a substitute.
81 | $query = explode(' AND ', $query);
82 | $query = $phrase ? str_replace(' ', '_', $query) : str_replace(' ', ',', $query);
83 | $query = implode(' AND ', $query);
84 |
85 | $offset = 0;
86 | while (true) {
87 | $response = $this->client->getJSON('/users', ['q' => $query, 'limit' => $batchSize, 'offset' => $offset]);
88 |
89 | // The API sometimes returns total_record_count: -1, with no further error message.
90 | // Seems to indicate that the query was not understood.
91 | // See: https://github.com/scriptotek/php-alma-client/issues/8
92 | if ($response->total_record_count == -1) {
93 | throw new InvalidQuery($query);
94 | }
95 |
96 | if ($response->total_record_count == 0) {
97 | break;
98 | }
99 |
100 | if (!isset($response->user) || empty($response->user)) {
101 | // We cannot trust the value in 'total_record_count', so if there are no more records,
102 | // we have to assume the result set is depleted.
103 | // See: https://github.com/scriptotek/php-alma-client/issues/7
104 | break;
105 | }
106 |
107 | foreach ($response->user as $data) {
108 | $offset++;
109 | // Contacts without a primary identifier will have the primary_id
110 | // field populated with something weird like "no primary id (123456789023)".
111 | // We ignore those.
112 | // See: https://github.com/scriptotek/php-alma-client/issues/6
113 | if (strpos($data->primary_id, 'no primary id') === 0) {
114 | continue;
115 | }
116 | $user = User::make($this->client, $data->primary_id)
117 | ->init($data);
118 | if ($expand) {
119 | $user->init();
120 | }
121 | yield $user;
122 | }
123 | if ($offset >= $response->total_record_count) {
124 | break;
125 | }
126 | if ($limit != 0 && $offset >= $limit) {
127 | break;
128 | }
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/Bibs/Item.php:
--------------------------------------------------------------------------------
1 | bib = $bib;
38 | $this->holding = $holding;
39 | $this->item_id = $item_id;
40 | $this->requests = Requests::make($this->client, $this->url('/requests'));
41 | }
42 |
43 | /**
44 | * Generate the base URL for this resource.
45 | *
46 | * @return string
47 | */
48 | protected function urlBase()
49 | {
50 | return "/bibs/{$this->bib->mms_id}/holdings/{$this->holding->holding_id}/items/{$this->item_id}";
51 | }
52 |
53 | /**
54 | * Check if we have the full representation of our data object.
55 | *
56 | * @param \stdClass $data
57 | *
58 | * @return bool
59 | */
60 | protected function isInitialized($data)
61 | {
62 | return isset($data->item_data);
63 | }
64 |
65 | /**
66 | * Called when data is available to be processed.
67 | *
68 | * @param mixed $data
69 | */
70 | protected function onData($data)
71 | {
72 | if (isset($this->bib_data)) {
73 | $this->bib->init($this->bib_data);
74 | }
75 | if (isset($this->holding_data)) {
76 | $this->holding->init($this->holding_data);
77 | }
78 | }
79 |
80 | /**
81 | * Create a new loan.
82 | *
83 | * @param User $user
84 | * @param Library $library
85 | * @param string $circ_desk
86 | *
87 | * @throws \Scriptotek\Alma\Exception\RequestFailed
88 | *
89 | * @return Loan
90 | */
91 | public function checkOut(User $user, Library $library, $circ_desk = 'DEFAULT_CIRC_DESK')
92 | {
93 | $postData = [
94 | 'library' => ['value' => $library->code],
95 | 'circ_desk' => ['value' => $circ_desk],
96 | ];
97 |
98 | $data = $this->client->postJSON(
99 | $this->url('/loans', ['user_id' => $user->id]),
100 | $postData
101 | );
102 |
103 | return Loan::make($this->client, $user, $data->loan_id)
104 | ->init($data);
105 | }
106 |
107 | /**
108 | * Perform scan-in on item.
109 | *
110 | * @param Library $library
111 | * @param string $circ_desk
112 | * @param array $params
113 | *
114 | * @throws \Scriptotek\Alma\Exception\RequestFailed
115 | *
116 | * @return ScanInResponse
117 | */
118 | public function scanIn(Library $library, $circ_desk = 'DEFAULT_CIRC_DESK', $params = [])
119 | {
120 | $params['op'] = 'scan';
121 | $params['library'] = $library->code;
122 | $params['circ_desk'] = $circ_desk;
123 |
124 | $data = $this->client->postJSON($this->url('', $params));
125 |
126 | return ScanInResponse::make($this->client, $data);
127 | }
128 |
129 | /**
130 | * Get the current loan as a Loan object, or null if the item is not loaned out.
131 | *
132 | * @returns Loan|null
133 | */
134 | public function getLoan()
135 | {
136 | $data = $this->client->getJSON($this->url('/loans'));
137 |
138 | if ($data->total_record_count == 1) {
139 | return Loan::make(
140 | $this->client,
141 | User::make($this->client, $data->item_loan[0]->user_id),
142 | $data->item_loan[0]->loan_id
143 | )->init($data->item_loan[0]);
144 | }
145 | }
146 |
147 | public function __get($key)
148 | {
149 | if ($key == 'loan') {
150 | return $this->getLoan();
151 | }
152 |
153 | $this->init();
154 |
155 | if (isset($this->data->item_data->{$key})) {
156 | return $this->data->item_data->{$key};
157 | }
158 | if (isset($this->data->holding_data->{$key})) {
159 | return $this->data->holding_data->{$key};
160 | }
161 | if (isset($this->data->bib_data->{$key})) {
162 | return $this->data->bib_data->{$key};
163 | }
164 |
165 | return parent::__get($key);
166 | }
167 | }
168 |
--------------------------------------------------------------------------------