{"id":36972012,"url":"https://github.com/scriptotek/php-alma-client","last_synced_at":"2026-01-13T21:55:02.717Z","repository":{"id":32000887,"uuid":"35571779","full_name":"scriptotek/php-alma-client","owner":"scriptotek","description":"Simple PHP package for working with the Alma REST APIs.","archived":false,"fork":false,"pushed_at":"2023-03-30T15:44:58.000Z","size":394,"stargazers_count":27,"open_issues_count":12,"forks_count":6,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-08-10T02:52:11.615Z","etag":null,"topics":["alma","client-library"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/scriptotek.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-13T20:09:15.000Z","updated_at":"2024-05-23T03:56:11.000Z","dependencies_parsed_at":"2023-01-14T20:18:24.145Z","dependency_job_id":null,"html_url":"https://github.com/scriptotek/php-alma-client","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/scriptotek/php-alma-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scriptotek%2Fphp-alma-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scriptotek%2Fphp-alma-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scriptotek%2Fphp-alma-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scriptotek%2Fphp-alma-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scriptotek","download_url":"https://codeload.github.com/scriptotek/php-alma-client/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scriptotek%2Fphp-alma-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28401939,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alma","client-library"],"created_at":"2026-01-13T21:55:02.548Z","updated_at":"2026-01-13T21:55:02.704Z","avatar_url":"https://github.com/scriptotek.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://img.shields.io/travis/scriptotek/php-alma-client.svg)](https://travis-ci.org/scriptotek/php-alma-client)\n[![Scrutinizer code quality](https://scrutinizer-ci.com/g/scriptotek/php-alma-client/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/scriptotek/php-alma-client/?branch=master)\n[![StyleCI](https://styleci.io/repos/35571779/shield)](https://styleci.io/repos/35571779)\n[![Packagist](https://img.shields.io/packagist/v/scriptotek/alma-client.svg)](https://packagist.org/packages/scriptotek/alma-client)\n\n# php-alma-client\n\nSimple PHP package for working with the [Alma REST APIs](https://developers.exlibrisgroup.com/alma/apis).\nSOAP APIs will not be supported.\nCurrently, this package supports Bibs (read/write), Users and Analytics (read only).\nIt is integrated with [php-marc](https://github.com/scriptotek/php-marc) for editing MARC records.\nIf the package doesn't fit your needs, you might take a look at the alternative\n[php-alma](https://github.com/BCLibraries/php-alma) package.\n\n## Table of Contents\n\n  * [Install using Composer](#install-using-composer)\n  * [Initializing a client](#initializing-a-client)\n  * [Quick intro](#quick-intro)\n  * [Note about lazy-loading and existence-checking](#note-about-lazy-loading-and-existence-checking)\n  * [Bibs: Bibliographic records, Holdings, Representations, Portfolios](#bibs-bibliographic-records-holdings-representations-portfolios)\n     * [Getting a single record](#getting-a-single-record)\n     * [The MARC21 record](#the-marc21-record)\n     * [Searching for records](#searching-for-records)\n     * [Getting linked record from network zone](#getting-linked-record-from-network-zone)\n     * [Editing records](#editing-records)\n     * [Holdings and items](#holdings-and-items)\n     * [Item by barcode](#item-by-barcode)\n     * [Electronic portfolios and collections](#electronic-portfolios-and-collections)\n     * [Digital representation and files](#digital-representation-and-files)\n  * [Users, loans, fees and requests](#users-loans-fees-and-requests)\n     * [Search](#search)\n     * [Loans](#loans)\n     * [Fees](#fees)\n     * [Requests](#requests)\n  * [Analytics reports](#analytics-reports)\n     * [Column names](#column-names)\n     * [Filters](#filters)\n  * [Task lists](#task-lists)\n     * [Lending requests](#lending-requests)\n     * [Requested resources (pick from shelf)](#requested-resources-pick-from-shelf)\n  * [Jobs](#jobs)\n     * [Listing jobs](#listing-jobs)\n     * [Retrieving information about a specific job](#retrieving-information-about-a-specific-job)\n     * [Submitting a job](#submitting-a-job)\n  * [Automatic retries on errors](#automatic-retries-on-errors)\n  * [Laravel integration](#laravel-integration)\n     * [Customizing the HTTP client stack](#customizing-the-http-client-stack)\n  * [Future plans](#future-plans)\n\nCreated by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)\n\n## Install using Composer\n\nUse [Composer](https://getcomposer.org) to install sru-client with a HTTP library such as Guzzle:\n\n```bash\ncomposer require scriptotek/alma-client php-http/guzzle6-adapter http-interop/http-factory-guzzle\n```\n\nWe use [HTTP discovery](https://github.com/http-interop/http-factory-discovery) to discover\n[HTTP client](https://packagist.org/providers/psr/http-client-implementation) and\n[HTTP factory](https://packagist.org/providers/psr/http-factory-implementation) implementations,\nso Guzzle can be swapped with any other\n[PSR-17](https://www.php-fig.org/psr/psr-17/)/[PSR-18](https://www.php-fig.org/psr/psr-18/)-compatible library.\n\n## Initializing a client\n\nStart by initiating a new client with the API key you get at [Ex Libris Developer Network](https://developers.exlibrisgroup.com/):\n\n```php\nrequire_once('vendor/autoload.php');\nuse Scriptotek\\Alma\\Client as AlmaClient;\nuse Scriptotek\\Sru\\Client as SruClient;\n\n$alma = new AlmaClient('MY_SECRET_API_KEY', 'eu');\n```\n\nwhere `'eu'` is the region code for Europe (use `'na'` for North America or `'ap'` for Asia Pacific).\nBy default, the API entry point URL is generated from the region code,\nbut if you're connecting to the API through a proxy, you can configure a different URL:\n\n```\n$alma = new AlmaClient('MY_SECRET_API_KEY')\n    -\u003esetEntryPoint('https://gw-uio.intark.uh-it.no/alma/v1');\n```\n\nIf your Alma instance is connected to a network zone and you want to work\nwith bib records there, you can also add an API key for the network zone:\n\n```php\n$alma-\u003enz-\u003esetKey('MY_SECRET_NETWORK_ZONE_API_KEY');\n```\n\nIf you want search support, connect [an SRU client](https://github.com/scriptotek/php-sru-client):\n\n```php\n$alma-\u003esetSruClient(new SruClient(\n    'https://bibsys-k.alma.exlibrisgroup.com/view/sru/47BIBSYS_UBO',\n    ['version' =\u003e '1.2']\n));\n```\n\nYou can also connect an SRU client to the network zone SRU service:\n\n```php\n$alma-\u003enz-\u003esetSruClient(new SruClient(\n    'https://bibsys-k.alma.exlibrisgroup.com/view/sru/47BIBSYS_NETWORK',\n    ['version' =\u003e '1.2']\n));\n```\n\n## Quick intro\n\nThe library provides access to Bibs, Holdings and Items\nthrough `$alma-\u003ebibs`, Users (`$alma-\u003eusers`), Analytics reports\n(`$alma-\u003eanalytics`), Libraries (`$alma-\u003elibraries`), Task Lists (`$alma-\u003etaskLists`) and Jobs (`$alma-\u003ejobs`).\n\nTo fetch a Bib record:\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('990114012304702204');\n```\n\n## Note about lazy-loading and existence-checking\n\nLazy loading: Note that the client uses lazy loading to reduce the number of HTTP\nrequests. Requests are not made when you instantiate objects, but when you request\ndata from them. So in this case, a HTTP request for the holding record is first\nmade when you call `getRecord()`. The response is then cached on the object for\nre-use. In the same way, no HTTP request is made for the Bib record in this case,\nsince we don't request any data from that.\n\n\nIn general the library delays fetching data until it's actually needed, a practice\ncalled lazy-loading. This means you can for instance initialize a `Bib` object and echo\nback the MMS id without any network requests taking place, since there is no need to\nfetch any data yet:\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('9901140123047044111');\necho $bib-\u003emms_id;\n```\n\nIf you request anything else on the Bib object, like the title, the data will automatically\nbe fetched and populated on the object:\n\n```php\necho $bib-\u003etitle;\n```\n\nIf the resource did not exist, a `ResourceNotFound` exception would be thrown at this point.\nSo you could go ahead and handle that case like so:\n\n```php\n\n$bib = $alma-\u003ebibs-\u003eget('9901140123047044111');\ntry {\n    echo $bib-\u003etitle;\n} catch (\\Scriptotek\\Alma\\Exception\\ResourceNotFound $exc) {\n    // Handle the case when the record doesn't exist\n}\n```\n\nBut you can also use the `exists()` method, which is often more convenient:\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('9901140123047044111');\nif (!$bib-\u003eexists()) {\n    // Handle the case when the record doesn't exist\n}\n```\n\n## Bibs: Bibliographic records, Holdings, Representations, Portfolios\n\n### Getting a single record\n\nA bibliographic record can be fetched either by MMS ID:\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('990114012304702204');\n```\n\nor by barcode:\n\n```php\n$bib = $alma-\u003ebibs-\u003efromBarcode('92nf02526');\n```\n\nNote: This methods returns null if the barcode is not found, as does the two methods below.\n\nThere are also two lookup methods that use SRU search and require that you have\nan SRU client attached. The first lets you use a generic CQL query:\n\n```php\n$bib = $alma-\u003ebibs-\u003efindOne('alma.all_for_ui=\"9788299308922\"');\n```\n\nThe second is a shorthand for looking up records from ISBN:\n\n```php\n$bib = $alma-\u003ebibs-\u003efromIsbn('9788299308922');\n```\n\nAll the methods above returns either a single `Bib` record or `null` if not found.\n\n### The MARC21 record\n\nThe MARC21 record is available as `$bib-\u003erecord` in the form of a\n[php-marc](https://github.com/scriptotek/php-marc/blob/master/src/Record.php) `Record` object\nthat extends `File_MARC_Record` from [File_MARC](https://github.com/pear/File_MARC),\nmeaning you can use all File_MARC methods in addition to the convenience methods from php-marc.\n\n### Searching for records\n\nIf you have connected an SRU client (described above), you can search using\nCQL search syntax like so:\n\n```php\nforeach ($alma-\u003ebibs-\u003esearch('alma.dewey_decimal_class_number=530.12') as $bib) {\n\t$marcRecord = $bib-\u003erecord;\n\techo \"$marcRecord-\u003eid: $marcRecord-\u003etitle\\n\";\n}\n```\n\n### Getting linked record from network zone\n\nIf you have configured a network zone API key (see above), you can easily\nget the network zone record connected to the institution zone record like so:\n\n```php\n$nzBib = $bib-\u003egetNzRecord();\n```\n\n### Editing records\n\nThe MARC21 record can be edited using the `File_MARC_Record` interface\n(see [File_MARC](https://github.com/pear/File_MARC) for documentation),\nand then saved back to Alma using the `save()` method on the `Bib` object.\nIn the example below we delete a subject heading and add another:\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('990114012304702204');\n\nforeach ($bib-\u003erecord-\u003egetSubjects() as $subject) {\n    if ($subject-\u003evocabulary == 'noubomn' \u0026\u0026 (string) $subject == 'Boating with dogs') {\n        $subject-\u003edelete();\n    }\n}\n\n$bib-\u003erecord-\u003eappendField(new File_MARC_Data_Field('650', [\n    new File_MARC_Subfield('a', 'Boating with cats'),\n    new File_MARC_Subfield('2', 'noubomn'),\n], null, '0'));\n\n$bib-\u003esave();\n```\n\n### Holdings and items\n\nThe `Bib` object provides easy access to holdings through the `holdings` iterator:\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('990310361044702204');\nforeach ($bib-\u003eholdings as $holding) {\n    echo \"{$holding-\u003eholding_id} {$holding-\u003ecall_number}\";\n}\n```\n\nAs with the `Bib` object, the MARC record for the `Holding` object is available\neither from the `getRecord()` method or the `record` property:\n\n```php\n$holding = $alma-\u003ebibs['990310361044702204']-\u003eholdings['22102913020002204'];\n$marcRecord = $holding-\u003erecord;\n```\n\n**Note:** Editing holding records is not yet supported. Will be added in the future.\n\nItems can be listed from holdings in the same manner as holdings can be fetched from bibs.\nHere's an example:\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('990310361044702204');\nforeach ($bib-\u003eholdings as $holding) {\n    foreach ($holding-\u003eitems as $item) {\n        echo \"{$item-\u003eholding_id} {$item-\u003epid} {$item-\u003ebarcode} : \";\n        echo \"{$item-\u003elocation-\u003edesc} {$item-\u003ecall_number} : \";\n        echo \"{$item-\u003ebase_status-\u003edesc} {$item-\u003eprocess_type-\u003edesc}\";\n        echo \"\\n\";\n    }\n}\n```\n\nIn this case, the client makes one request to fetch the list of holdings, and\nthen one request per holding to fetch items.\n\n### Item by barcode\n\nThere is a special entrypoint to retrieve an item by barcode:\n\n```php\n$item = $alma-\u003eitems-\u003efromBarcode('92nf02526');\n```\n\n### Electronic portfolios and collections\n\nElectronic portfolios and collections are available on the `Bib` object in the same way as holdings.\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('990310361044702204');\nforeach ($bib-\u003eportfolios as $portfolio) {\n    echo \"{$portfolio-\u003eportfolio_id} {$portfolio-\u003eelectronic_collection-\u003eservice-\u003elink} \";\n    echo \"{$portfolio-\u003eelectronic_collection-\u003epublic_name}\\n\";\n}\n```\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('990310361044702204');\nforeach ($bib-\u003eelectronic_collections as $collection) {\n    echo \"{$collection-\u003epublic_name}\";\n}\n```\n\n### Digital representation and files\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('990310361044702204');\nforeach ($bib-\u003erepresentations as $rep) {\n    echo \"{$rep-\u003erepresentation_id} {$rep-\u003elabel}\\n\";\n    foreach ($rep-\u003efiles as $rep_file) {\n        echo \"{$rep_file-\u003elabel} {$rep_file-\u003ethumbnail_url}\\n\";\n    }\n}\n```\n\n## Users, loans, fees and requests\n\n**Note**: Editing is not yet implemented.\n\n### Search\n\nExample:\n\n```php\nforeach ($alma-\u003eusers-\u003esearch('last_name~Heggø AND first_name~Dan') as $user) {\n    echo \"{$user-\u003efirst_name} {$user-\u003elast_name} ({$user-\u003eprimary_id})\\n\";\n}\n```\n\n### Loans\n\nExample:\n\n```php\n\nforeach ($user-\u003eloans as $loan) {\n    echo \"{$loan-\u003edue_date} {$loan-\u003etitle}\\n\";\n}\n```\n\nNote that `$user-\u003eloans` is an iterator. To get an array instead,\nyou can use `iterator_to_array($user-\u003eloans)`.\n\n### Fees\n\nExample:\n\n```php\nprintf('Total: %s %s', $user-\u003efees-\u003etotal_sum, $user-\u003efees-\u003ecurrency);\n\nforeach ($user-\u003efees as $fee) {\n    echo \"{$fee-\u003etype-\u003evalue}\\t{$fee-\u003ebalance}\\t{$fee-\u003etitle}\\n\";\n}\n```\n\n### Requests\n\nExample:\n\n```php\nforeach ($user-\u003erequests as $request) {\n    echo json_encode($request, JSON_PRETTY_PRINT);\n}\n```\n\nRequests can also be retrieved from a `Bib` object or an `Item` object.\n\n## Analytics reports\n\nTo retrieve the results from a single report:\n\n```php\n$report = $alma-\u003eanalytics-\u003eget('/shared/Alma/Item Historical Events/Reports/Items went into temporary location');\nforeach ($report as $row) {\n    echo implode(\"\\t\", $row) . \"\\n\";\n}\n```\n\nThe rows are returned using a generator that takes care of fetching more rows until\nthe result set is depleted, so you don't have to think about continuation. If you only\nwant a subset of the rows, you must take care of breaking out of the loop yourself.\n\n### Column names\n\nThe column names can be accessed through `headers`:\n\n```php\n$report = $alma-\u003eanalytics-\u003eget('/shared/Alma/Item Historical Events/Reports/Items went into temporary location');\nforeach ($report-\u003eheaders as $header) {\n    echo \"$header\\n\";\n}\n```\n\nThe column names can be accessed through can also be used to access columns for a given row:\n\n```php\nforeach ($report as $row) {\n    echo $row['Title'] . \"\\n\";\n}\n```\n\nIf you would rather use other column names than the ones defined in Analytics\nit is also possible to override them by passing in an array of names that must\nfollow the same order as the columns in the report:\n\n```php\n$report = $alma-\u003eanalytics-\u003eget(\n    '/shared/Alma/Item Historical Events/Reports/Items went into temporary location',\n    [\n        'mms_id',\n        'receiving_date',\n    ]\n);\nforeach ($report-\u003erows as $row) {\n    echo $row-\u003emms_id . \": \" . $row-\u003ereceiving_date . \"\\n\";\n}\n```\n\n\n### Filters\n\nThe method also accepts a filter.\n\n```php\n$report = $alma-\u003eanalytics-\u003eget(\n    '/shared/Alma/Item Historical Events/Reports/Items went into temporary location',\n    [\n        'mms_id',\n        'receiving_date',\n    ],\n    '\u003csawx:expr op=\"greaterOrEqual\" xsi:type=\"sawx:comparison\"\n                   xmlns:sawx=\"com.siebel.analytics.web/expression/v1.1\"\n                   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\u003e\n       \u003csawx:expr xsi:type=\"sawx:sqlExpression\"\u003e\"Physical Item Details\".\"Receiving   Date\"\u003c/sawx:expr\u003e\n       \u003csawx:expr xsi:type=\"sawx:sqlExpression\"\u003eTIMESTAMPADD(SQL_TSI_DAY, -1, CURRENT_DATE)\u003c/sawx:expr\u003e\n    \u003c/sawx:expr\u003e',\n);\nforeach ($report-\u003erows as $row) {\n    echo $row-\u003emms_id . \": \" . $row-\u003ereceiving_date . \"\\n\";\n}\n```\n\nThere isn't much official documentation on filters, and error responses from the\nAPI are generally not useful, but there's some helpful hints in\n[this blog post](https://developers.exlibrisgroup.com/blog/Working-with-Analytics-REST-APIs).\n\nMy experience so far is that including a \"is prompted\" filter in the report is\nreally needed. Otherwise the query returns a `400 No more rows to fetch`\n(after a looong wait).\n\nFurthermore, I've *not* been successful with pure SQL filters. In OBI you can\nconvert a filter to SQL. The results looks like this:\n\n```xml\n\u003csawx:expr xmlns:saw=\"com.siebel.analytics.web/report/v1.1\" xmlns:sawx=\"com.siebel.analytics.web/expression/v1.1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"sawx:sawx:sql\"\u003e\"Physical Item Details\".\"Receiving   Date\" \u0026gt;=  TIMESTAMPADD(SQL_TSI_DAY, -1, CURRENT_DATE)\u003c/sawx:expr\u003e\n```\n\nBut used with the API, the response is the same as if you forget to include an\n\"is prompted\" filter: a loong wait follow by a \"400 No more rows to fetch\".\n\n## Task lists\n\n### Lending requests\n\n````php\n$library = $alma-\u003econf-\u003elibraries['LIBRARY_CODE'];\n$requests = $alma-\u003etaskLists-\u003egetLendingRequests($library, [\n    'printed' =\u003e 'N',\n    'status' =\u003e 'REQUEST_CREATED_LEND',\n]);\nforeach ($requests as $request) {\n    echo \"- {$request-\u003erequest_id} {$request-\u003estatus}\\n\";\n}\n````\n\nNote: As of 2018-10-13, there is a bug preventing you from retrieving more than 100 lending requests.\n\n### Requested resources (pick from shelf)\n\n```php\n$library = $alma-\u003elibraries['LIBRARY_CODE'];\n$requests = $alma-\u003etaskLists-\u003egetRequestedResources($library, 'DEFAULT_CIRC_DESK', [\n    'printed' =\u003e 'N',\n]);\nforeach ($requests as $request) {\n    echo \"- {$request-\u003eresource_metadata-\u003etitle} {$request-\u003eresource_metadata-\u003emms_id-\u003evalue}\\n\";\n}\n```\n\n## Jobs\n\n### Listing jobs\n\nTo list all jobs and their instances:\n\n```php\nforeach ($alma-\u003ejobs as $job) {\n    echo \"[{$job-\u003eid}] {$job-\u003ename} / {$job-\u003edescription}\\n\";\n    foreach ($job-\u003einstances as $instance) {\n        echo \"    [{$instance-\u003eid}] Status: {$instance-\u003estatus-\u003edesc}\\n\";\n    }\n}\n```\n\nThis is a generator, so you can start processing results before the full list has been retrieved (it fetches jobs in batches of 10).\n\n### Retrieving information about a specific job\n\n```php\n$job = $alma-\u003ejobs['M43'];\n```\n\n### Submitting a job\n\n```php\n$instance = $alma-\u003ejobs['M43']-\u003esubmit();\n```\n\n## Automatic retries on errors\n\nIf the client receives a 429 (rate limiting) response from Alma, it will sleep for a short time (0.5 seconds by default)\nand retry the request a configurable number of times (10 by default), before giving up and throwing a\n`Scriptotek\\Alma\\Exception\\MaxNumberOfAttemptsExhausted`.\nBoth the max number of attempts and the sleep time can be configured:\n\n```php\n$client-\u003emaxAttempts = 5;\n$client-\u003esleepTimeOnRetry = 3;  // seconds\n```\n\nIf the client receives a 5XX server error, it will by default not retry the request, but this can be configured.\nThis can be useful when retrieving large Analytics reports, which have a tendency to fail intermittently.\n\n```php\n$client-\u003emaxAttemptsOnServerError = 10;\n$client-\u003esleepTimeOnServerError = 10;  // seconds\n```\n\nWhen the number of retries have been exhausted, a `Scriptotek\\Alma\\Exception\\RequestFailed` exception is thrown.\n\n## Laravel integration\n\nThis project ships with an auto-discoverable service provider and facade. Run\n\n    $ php artisan vendor:publish --provider=\"Scriptotek\\Alma\\Laravel\\ServiceProvider\"\n\nto create the `config/alma.php` configuration file.\n\nIf you are on Laravel 5.4 or older, you must manually add the service provider to the\n`$providers` array in your `config/app.php`:\n\n    Scriptotek\\Alma\\Laravel\\ServiceProvider::class,\n\nAnd the facade:\n\n    'Alma' =\u003e Scriptotek\\Alma\\Laravel\\Facade::class,\n\n### Customizing the HTTP client stack\n\nIf the Laravel [Service Container](https://laravel.com/docs/master/providers)\ncontains a PSR-18 HTTP Client bound to `Psr\\Http\\Client\\ClientInterface`,\nAlma Client will use that implementation instead of instantiating its own HTTP\nclient.\n\nHere's an example service provider that registers a HTTP client with some middleware\nfrom [php-http/client-common](http://docs.php-http.org/en/latest/plugins/introduction.html#install):\n\n```php\n\u003c?php\n\nnamespace App\\Providers;\n\nuse Http\\Client\\Common\\Plugin\\ContentLengthPlugin;\nuse Http\\Client\\Common\\Plugin\\ErrorPlugin;\nuse Http\\Client\\Common\\Plugin\\RetryPlugin;\nuse Http\\Client\\Common\\PluginClient;\nuse Http\\Factory\\Discovery\\HttpClient;\nuse Illuminate\\Support\\ServiceProvider;\nuse Psr\\Http\\Client\\ClientInterface;\n\nclass HttpServiceProvider extends ServiceProvider\n{\n    public function register()\n    {\n        $this-\u003eapp-\u003esingleton(ClientInterface::class, function($app) {\n            return new PluginClient(\n                HttpClient::client(),\n                [\n                    new ContentLengthPlugin(),\n                    new RetryPlugin([\n                        'retries' =\u003e 10,\n                    ]),\n                    new ErrorPlugin(),\n                ]\n            );\n        });\n    }\n}\n```\n\n## Future plans\n\n- Better support for editing, perhaps better integration with the php-marc package to provide a fluent editing interface:\n\n```php\n$bib = $alma-\u003ebibs-\u003eget('990114012304702204');  // a Bib object\n$bib-\u003erecord-\u003esubjects-\u003eadd([\n\t'term' =\u003e 'Boating with cats',\n\t'vocabulary' =\u003e noubomn'\n]);\n$bib-\u003esave()\n```\n\n- Support for creating records and users:\n\n```php\n$bib = new Bib();\n$alma-\u003ebibs-\u003estore($bib);\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscriptotek%2Fphp-alma-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscriptotek%2Fphp-alma-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscriptotek%2Fphp-alma-client/lists"}