😎
(非標準)Omeka SのOAI-PMH RepositoryモジュールでDeleteレコードを出力してみる
概要
Omeka SのOAI-PMH RepositoryモジュールでDeleteレコードを出力してみましたので、備忘録です。
背景
以下のモジュールを使用することにより、OAI-PMHのリポジトリ機能を構築することができます。
ただ、確認した限り、Deleteレコードを出力する機能はないようでした。
関連モジュール
Omekaの標準機能では、削除されたリソースを保存する機能はないかと思います。
一方、以下のモジュールは削除されたリソースを保持する機能を追加します。
本モジュールを有効化することにより、以下のように、リソースがいつ誰によって削除されたかを記録できるようになりました。
OAI-PMH Repositoryモジュールへの応用
上記のモジュールで作成される削除されたリソースの情報が格納されるテーブルを使って、Deleteレコードの出力を試みます。
以下のファイルのlistResponse関数に追記します。
OaiPmhRepository/src/OaiPmh/ResponseGenerator.php
private function listResponse($verb, $metadataPrefix, $cursor, $set, $from, $until): void
{
/**
* @var \Omeka\Api\Adapter\Manager $apiAdapterManager
* @var \Doctrine\ORM\EntityManager $entityManager
*/
$apiAdapterManager = $this->serviceLocator->get('Omeka\ApiAdapterManager');
$entityManager = $this->serviceLocator->get('Omeka\EntityManager');
$itemRepository = $entityManager->getRepository(\Omeka\Entity\Item::class);
$qb = $itemRepository->createQueryBuilder('omeka_root');
$qb->select('omeka_root');
$query = new ArrayObject;
$expr = $qb->expr();
// 以下を追加
if ($set === 'o:deleted') {
$settings = $this->serviceLocator->get('Omeka\Settings');
$namespaceId = $settings->get('oaipmhrepository_namespace_id', 'default_namespace');
// 削除済みレコードを necropolis_resource テーブルから取得する
$deletedResourceRepository = $entityManager->getRepository(\Necropolis\Entity\NecropolisResource::class); // カスタムエンティティ
// oaipmhrepository_expose_mediaに応じて、mediaとitemの取得を分ける
$exposeMedia = $settings->get('oaipmhrepository_expose_media', false); // デフォルトはfalse(itemのみ)
if ($exposeMedia) {
$qb = $deletedResourceRepository->createQueryBuilder('necropolis_resource');
} else {
// Itemのみを取得する
$qb = $deletedResourceRepository->createQueryBuilder('necropolis_resource')
->andWhere('necropolis_resource.resourceType = :itemType')
->setParameter('itemType', 'Omeka\Entity\Item');
}
// 日付フィルタリング
if ($from) {
$qb->andWhere($expr->gte('necropolis_resource.deleted', ':from'));
$qb->setParameter('from', $from);
}
if ($until) {
$qb->andWhere($expr->lte('necropolis_resource.deleted', ':until'));
$qb->setParameter('until', $until);
}
// 結果の制限とオフセット
$qb->setMaxResults($this->_listLimit);
$qb->setFirstResult($cursor);
$paginator = new Paginator($qb, false);
$rows = count($paginator);
if ($rows == 0) {
$this->throwError(self::OAI_ERR_NO_RECORDS_MATCH, new Message('No records match the given criteria.')); // @translate
} else {
if ($verb == 'ListIdentifiers') {
$method = 'appendHeader';
} elseif ($verb == 'ListRecords') {
$method = 'appendRecord';
}
$verbElement = $this->document->createElement($verb);
$this->document->documentElement->appendChild($verbElement);
foreach ($paginator as $deletedEntity) {
// 削除されたリソースの情報をOAI-PMHレスポンスに追加
$header = $this->document->createElement('header');
$header->setAttribute('status', 'deleted'); // 削除済みレコードとして設定
$identifier = $this->document->createElement('identifier', 'oai:' . $namespaceId . ":" . $deletedEntity->getId());
$header->appendChild($identifier);
$datestamp = $this->document->createElement('datestamp', $deletedEntity->getDeleted()->format('Y-m-d\TH:i:s\Z'));
$header->appendChild($datestamp);
$verbElement->appendChild($header);
}
// Resumption Token の処理
if ($rows > ($cursor + $this->_listLimit)) {
$token = $this->createResumptionToken($verb, $metadataPrefix,
$cursor + $this->_listLimit, $set, $from, $until);
$tokenElement = $this->document->createElement('resumptionToken', (string) $token->id());
$tokenElement->setAttribute('expirationDate', $token->expiration()->format('Y-m-d\TH:i:s\Z'));
$tokenElement->setAttribute('completeListSize', (string) $rows);
$tokenElement->setAttribute('cursor', (string) $cursor);
$verbElement->appendChild($tokenElement);
} elseif ($cursor != 0) {
$tokenElement = $this->document->createElement('resumptionToken');
$verbElement->appendChild($tokenElement);
}
}
return;
}
...
OAI-PMH標準には合致していない実装方法ですが、setにo:deletedを指定すると、削除レコードを返却することができます。
例えば、以下です。xslへの対応などは今後の課題です。
https://omeka.aws.ldas.jp/oai?verb=ListRecords&metadataPrefix=oai_dc&set=o:deleted&from=2024-01-01
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="/modules/OaiPmhRepository/asset/xsl/oai-pmh-repository.xsl?v=3.4.9"?>
<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">
<responseDate>2024-10-10T07:50:56Z</responseDate>
<request verb="ListRecords" metadataPrefix="oai_dc" set="o:deleted" from="2024-01-01">https://omeka.aws.ldas.jp/oai</request>
<ListRecords>
<header status="deleted">
<identifier>oai:omeka.aws.ldas.jp:41</identifier>
<datestamp>2024-10-10T07:06:01Z</datestamp>
</header>
</ListRecords>
</OAI-PMH>
resumptionTokenも動作することを確認しました。
まとめ
上記の実装を工夫することで、OAI-PMHの標準に合致するように削除レコードを出力できるかもしれません。
色々と検証できていない点がありますが、参考になりましたら幸いです。
Discussion