scriptotek/alma-client

与一些Alma API交互的包

v0.9.3 2021-04-14 14:50 UTC

README

Build Status Scrutinizer code quality StyleCI Packagist

php-alma-client

一个简单的PHP包,用于处理Alma REST APIs。不支持SOAP API。目前,此包支持Bibs(读写)、用户和数据分析(只读)。它集成了php-marc以编辑MARC记录。如果此包不符合您的需求,您可以查看替代的php-alma包。

目录

gh-md-toc 创建

使用Composer安装

使用 Composer 安装带有HTTP库(如Guzzle)的sru-client

composer require scriptotek/alma-client php-http/guzzle6-adapter http-interop/http-factory-guzzle

我们使用 HTTP发现 来发现 HTTP客户端HTTP工厂 实现,因此Guzzle可以与其他任何 PSR-17/PSR-18-兼容的库交换。

初始化客户端

首先,使用您在 Ex Libris开发者网络 获取的API密钥启动新的客户端

require_once('vendor/autoload.php');
use Scriptotek\Alma\Client as AlmaClient;
use Scriptotek\Sru\Client as SruClient;

$alma = new AlmaClient('MY_SECRET_API_KEY', 'eu');

其中 'eu' 是欧洲的地区代码(使用 'na' 表示北美或 'ap' 表示亚太地区)。默认情况下,API入口点URL根据地区代码生成,但如果您通过代理连接到API,则可以配置不同的URL

$alma = new AlmaClient('MY_SECRET_API_KEY')
    ->setEntryPoint('https://gw-uio.intark.uh-it.no/alma/v1');

如果您的Alma实例连接到网络区域,并且您想要处理那里的Bibs记录,您还可以添加网络区域的API密钥

$alma->nz->setKey('MY_SECRET_NETWORK_ZONE_API_KEY');

如果您需要搜索支持,请连接 SRU客户端

$alma->setSruClient(new SruClient(
    'https://bibsys-k.alma.exlibrisgroup.com/view/sru/47BIBSYS_UBO',
    ['version' => '1.2']
));

您还可以将SRU客户端连接到网络区域SRU服务

$alma->nz->setSruClient(new SruClient(
    'https://bibsys-k.alma.exlibrisgroup.com/view/sru/47BIBSYS_NETWORK',
    ['version' => '1.2']
));

快速入门

该库通过 $alma->bibs、用户($alma->users)、分析报告($alma->analytics)、图书馆($alma->libraries)、任务列表($alma->taskLists)和作业($alma->jobs)提供对Bibs、馆藏和项目的访问。

获取Bib记录

$bib = $alma->bibs->get('990114012304702204');

关于延迟加载和存在检查的说明

懒加载:注意客户端使用懒加载来减少HTTP请求的数量。当实例化对象时不会发出请求,而是在请求数据时才会发出请求。因此,在这种情况下,第一次调用getRecord()时才会发出获取持证记录的HTTP请求。然后,响应会被缓存在对象中以供重用。同样,在这种情况下,不会为Bib记录发出HTTP请求,因为我们没有从该记录请求任何数据。

通常情况下,图书馆会延迟加载数据,直到实际需要时,这种做法称为懒加载。这意味着您可以初始化一个Bib对象,并回显MMS ID,而不需要进行任何网络请求,因为目前尚不需要获取任何数据。

$bib = $alma->bibs->get('9901140123047044111');
echo $bib->mms_id;

如果您请求Bib对象上的其他任何内容,例如标题,数据将自动从网络上获取并填充到对象中。

echo $bib->title;

如果资源不存在,此时会抛出ResourceNotFound异常。因此,您可以像这样处理该情况。

$bib = $alma->bibs->get('9901140123047044111');
try {
    echo $bib->title;
} catch (\Scriptotek\Alma\Exception\ResourceNotFound $exc) {
    // Handle the case when the record doesn't exist
}

但您也可以使用exists()方法,这通常更方便。

$bib = $alma->bibs->get('9901140123047044111');
if (!$bib->exists()) {
    // Handle the case when the record doesn't exist
}

Bibs:书目记录、馆藏、表示、组合

获取单个记录

可以通过MMS ID或条形码来获取书目记录。

$bib = $alma->bibs->get('990114012304702204');

或通过条形码

$bib = $alma->bibs->fromBarcode('92nf02526');

注意:如果找不到条形码,此方法和下面的两个方法都会返回null。

此外,还有两个使用SRU搜索的查找方法,要求您已连接SRU客户端。第一个允许您使用通用的CQL查询。

$bib = $alma->bibs->findOne('alma.all_for_ui="9788299308922"');

第二个是查找ISBN记录的简称。

$bib = $alma->bibs->fromIsbn('9788299308922');

上述所有方法都返回单个Bib记录,如果未找到则返回null

MARC21记录

MARC21记录以$bib->record的形式作为php-marc Record对象提供,该对象扩展自File_MARC_Record,这意味着您可以使用所有File_MARC方法以及php-marc的便利方法。

搜索记录

如果您已连接SRU客户端(如上所述),可以使用CQL搜索语法进行搜索。

foreach ($alma->bibs->search('alma.dewey_decimal_class_number=530.12') as $bib) {
	$marcRecord = $bib->record;
	echo "$marcRecord->id: $marcRecord->title\n";
}

从网络区域获取相关记录

如果您已配置网络区域API密钥(见上),可以轻松获取与机构区域记录连接的网络区域记录。

$nzBib = $bib->getNzRecord();

编辑记录

可以使用File_MARC_Record接口(见File_MARC文档)编辑MARC21记录,然后使用Bib对象的save()方法将其保存回Alma。以下示例中,我们删除了一个主题标题并添加了另一个。

$bib = $alma->bibs->get('990114012304702204');

foreach ($bib->record->getSubjects() as $subject) {
    if ($subject->vocabulary == 'noubomn' && (string) $subject == 'Boating with dogs') {
        $subject->delete();
    }
}

$bib->record->appendField(new File_MARC_Data_Field('650', [
    new File_MARC_Subfield('a', 'Boating with cats'),
    new File_MARC_Subfield('2', 'noubomn'),
], null, '0'));

$bib->save();

馆藏和项目

Bib对象通过holdings迭代器提供对馆藏的简单访问。

$bib = $alma->bibs->get('990310361044702204');
foreach ($bib->holdings as $holding) {
    echo "{$holding->holding_id} {$holding->call_number}";
}

Bib对象一样,Holding对象的MARC记录可以通过getRecord()方法或record属性获取。

$holding = $alma->bibs['990310361044702204']->holdings['22102913020002204'];
$marcRecord = $holding->record;

注意:编辑馆藏记录尚不支持。将在未来添加。

可以以与从Bib获取馆藏相同的方式列出项目。

$bib = $alma->bibs->get('990310361044702204');
foreach ($bib->holdings as $holding) {
    foreach ($holding->items as $item) {
        echo "{$item->holding_id} {$item->pid} {$item->barcode} : ";
        echo "{$item->location->desc} {$item->call_number} : ";
        echo "{$item->base_status->desc} {$item->process_type->desc}";
        echo "\n";
    }
}

在这种情况下,客户端发出一个请求来获取馆藏列表,然后对每个馆藏发出一个请求来获取项目。

通过条形码获取项目

有一个特殊的入口点可以按条形码检索项目。

$item = $alma->items->fromBarcode('92nf02526');

电子组合和集合

电子组合和集合以与馆藏相同的方式在Bib对象上提供。

$bib = $alma->bibs->get('990310361044702204');
foreach ($bib->portfolios as $portfolio) {
    echo "{$portfolio->portfolio_id} {$portfolio->electronic_collection->service->link} ";
    echo "{$portfolio->electronic_collection->public_name}\n";
}
$bib = $alma->bibs->get('990310361044702204');
foreach ($bib->electronic_collections as $collection) {
    echo "{$collection->public_name}";
}

数字表示和文件

$bib = $alma->bibs->get('990310361044702204');
foreach ($bib->representations as $rep) {
    echo "{$rep->representation_id} {$rep->label}\n";
    foreach ($rep->files as $rep_file) {
        echo "{$rep_file->label} {$rep_file->thumbnail_url}\n";
    }
}

用户、借阅、费用和请求

注意:编辑尚未实现。

搜索

示例

foreach ($alma->users->search('last_name~Heggø AND first_name~Dan') as $user) {
    echo "{$user->first_name} {$user->last_name} ({$user->primary_id})\n";
}

借阅

示例

foreach ($user->loans as $loan) {
    echo "{$loan->due_date} {$loan->title}\n";
}

注意,$user->loans是一个迭代器。要获取数组,可以使用iterator_to_array($user->loans)

费用

示例

printf('Total: %s %s', $user->fees->total_sum, $user->fees->currency);

foreach ($user->fees as $fee) {
    echo "{$fee->type->value}\t{$fee->balance}\t{$fee->title}\n";
}

请求

示例

foreach ($user->requests as $request) {
    echo json_encode($request, JSON_PRETTY_PRINT);
}

也可以从Bib对象或Item对象检索请求。

分析报告

要从单个报告中检索结果

$report = $alma->analytics->get('/shared/Alma/Item Historical Events/Reports/Items went into temporary location');
foreach ($report as $row) {
    echo implode("\t", $row) . "\n";
}

行通过一个生成器返回,该生成器负责检索更多行直到结果集耗尽,因此您无需考虑继续。如果您只想获取部分行,您必须自己退出循环。

列名

列名可以通过 headers 访问

$report = $alma->analytics->get('/shared/Alma/Item Historical Events/Reports/Items went into temporary location');
foreach ($report->headers as $header) {
    echo "$header\n";
}

列名也可以用来访问特定行的列

foreach ($report as $row) {
    echo $row['Title'] . "\n";
}

如果您想使用与Analytics中定义的不同列名,也可以通过传递一个数组来覆盖它们,该数组必须遵循报告中列的相同顺序

$report = $alma->analytics->get(
    '/shared/Alma/Item Historical Events/Reports/Items went into temporary location',
    [
        'mms_id',
        'receiving_date',
    ]
);
foreach ($report->rows as $row) {
    echo $row->mms_id . ": " . $row->receiving_date . "\n";
}

过滤器

此方法还接受一个过滤器。

$report = $alma->analytics->get(
    '/shared/Alma/Item Historical Events/Reports/Items went into temporary location',
    [
        'mms_id',
        'receiving_date',
    ],
    '<sawx:expr op="greaterOrEqual" xsi:type="sawx:comparison"
                   xmlns:sawx="com.siebel.analytics.web/expression/v1.1"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
       <sawx:expr xsi:type="sawx:sqlExpression">"Physical Item Details"."Receiving   Date"</sawx:expr>
       <sawx:expr xsi:type="sawx:sqlExpression">TIMESTAMPADD(SQL_TSI_DAY, -1, CURRENT_DATE)</sawx:expr>
    </sawx:expr>',
);
foreach ($report->rows as $row) {
    echo $row->mms_id . ": " . $row->receiving_date . "\n";
}

关于过滤器的官方文档不多,API的错误响应通常也不太有用,但这篇博客文章中提供了一些有用的提示。

我的经验是,在报告中包含一个“被提示”的过滤器是非常必要的。否则,查询将返回一个 400 No more rows to fetch(经过长时间的等待)。

此外,我使用纯SQL过滤器没有成功。在OBI中,您可以将过滤器转换为SQL。结果看起来像这样

<sawx: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">"Physical Item Details"."Receiving   Date" &gt;=  TIMESTAMPADD(SQL_TSI_DAY, -1, CURRENT_DATE)</sawx:expr>

但是与API一起使用时,响应与忘记包含“被提示”过滤器时的响应相同:长时间的等待后,出现“400 No more rows to fetch”。

任务列表

借阅请求

$library = $alma->conf->libraries['LIBRARY_CODE'];
$requests = $alma->taskLists->getLendingRequests($library, [
    'printed' => 'N',
    'status' => 'REQUEST_CREATED_LEND',
]);
foreach ($requests as $request) {
    echo "- {$request->request_id} {$request->status}\n";
}

注意:截至2018-10-13,有一个bug阻止您检索超过100个借阅请求。

请求的资源(从书架上选择)

$library = $alma->libraries['LIBRARY_CODE'];
$requests = $alma->taskLists->getRequestedResources($library, 'DEFAULT_CIRC_DESK', [
    'printed' => 'N',
]);
foreach ($requests as $request) {
    echo "- {$request->resource_metadata->title} {$request->resource_metadata->mms_id->value}\n";
}

作业

列出作业

列出所有作业及其实例

foreach ($alma->jobs as $job) {
    echo "[{$job->id}] {$job->name} / {$job->description}\n";
    foreach ($job->instances as $instance) {
        echo "    [{$instance->id}] Status: {$instance->status->desc}\n";
    }
}

这是一个生成器,因此您可以在完整列表检索到之前开始处理结果(它以10个作业的批次检索作业)。

检索特定作业的信息

$job = $alma->jobs['M43'];

提交作业

$instance = $alma->jobs['M43']->submit();

错误自动重试

如果客户端从Alma收到429(速率限制)响应,它将默认暂停一段时间(默认为0.5秒)并重试请求一个可配置的次数(默认为10次),然后放弃并抛出 Scriptotek\Alma\Exception\MaxNumberOfAttemptsExhausted。最大尝试次数和暂停时间都可以配置。

$client->maxAttempts = 5;
$client->sleepTimeOnRetry = 3;  // seconds

如果客户端收到5XX服务器错误,它默认不会重试请求,但这可以配置。当检索大型Analytics报告时,这可能很有用,因为这些报告有间歇性失败的趋势。

$client->maxAttemptsOnServerError = 10;
$client->sleepTimeOnServerError = 10;  // seconds

当重试次数耗尽时,将抛出 Scriptotek\Alma\Exception\RequestFailed 异常。

Laravel集成

此项目包含一个可自动发现的ServiceProvider和Facade。运行

$ php artisan vendor:publish --provider="Scriptotek\Alma\Laravel\ServiceProvider"

以创建 config/alma.php 配置文件。

如果您使用的是Laravel 5.4或更早版本,您必须手动将ServiceProvider添加到您的 config/app.php 中的 $providers 数组。

Scriptotek\Alma\Laravel\ServiceProvider::class,

以及Facade

'Alma' => Scriptotek\Alma\Laravel\Facade::class,

自定义HTTP客户端堆栈

如果Laravel的Service Container包含一个绑定到 Psr\Http\Client\ClientInterface 的PSR-18 HTTP客户端,Alma Client将使用该实现而不是实例化自己的HTTP客户端。

以下是一个示例ServiceProvider,它使用php-http/client-common的一些中间件注册了一个HTTP客户端

<?php

namespace App\Providers;

use Http\Client\Common\Plugin\ContentLengthPlugin;
use Http\Client\Common\Plugin\ErrorPlugin;
use Http\Client\Common\Plugin\RetryPlugin;
use Http\Client\Common\PluginClient;
use Http\Factory\Discovery\HttpClient;
use Illuminate\Support\ServiceProvider;
use Psr\Http\Client\ClientInterface;

class HttpServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(ClientInterface::class, function($app) {
            return new PluginClient(
                HttpClient::client(),
                [
                    new ContentLengthPlugin(),
                    new RetryPlugin([
                        'retries' => 10,
                    ]),
                    new ErrorPlugin(),
                ]
            );
        });
    }
}

未来计划

  • 更好的编辑支持,可能更好地与php-marc包集成以提供流畅的编辑界面
$bib = $alma->bibs->get('990114012304702204');  // a Bib object
$bib->record->subjects->add([
	'term' => 'Boating with cats',
	'vocabulary' => noubomn'
]);
$bib->save()
  • 支持创建记录和用户
$bib = new Bib();
$alma->bibs->store($bib);