NDK 支持开发 PHP 客户端,以连接北德教堂数据库

2.0.4 2024-02-15 12:56 UTC

README

NDK 支持开发 PHP 客户端,以连接北德福音路德教堂(北德教堂)的数据库。为此,它使用北德教堂 API(简称 "NAPI")来获取地址和活动数据。

可以通过 NAPI 读取哪些数据,可以在 NAPI 文档 中找到。相同的过滤器和对象属性也存在于 NDK 中。因此,可以将此文档与 IDE 或适当编辑器的 IntelliSense/Autocomplete 一起使用,以使用 NDK 和其对象。

NDK 不是与 NAPI 通信的先决条件。它仅提供创建自己的应用程序的工具。

在此项目中使用的命名空间符合 PSR-4 标准。因此,在此文档中不会直接引用文件,而是引用命名空间和类名。

安装

安装最新版本

$ composer require nordkirche/ndk

设置

<?php
$configuration = new \Nordkirche\Ndk\Configuration(
    getenv('NAPI_ID'),
    getenv('NAPI_ACCESSTOKEN')
);
$configuration->setNapiHost('www.nordkirche.de')->setNapiPath('api/');
$api = new \Nordkirche\Ndk\Api($configuration);

NDK 依赖于一个配置对象,该对象至少需要用 ID 和访问令牌以及官方 NAPI 终结点进行初始化,以包含访问数据。

这样就可以初始化 NDK API,以在配置过程中获取其他对象。

数据查询

可以通过存储库类查询数据。所有可用的类都位于 \Nordkirche\Ndk\Domain\Repository 下。

可以通过查询类定义查询的过滤器和参数。所有查询类都位于 \Nordkirche\Ndk\Domain\Query 下。

所有存储库都可以使用 \Nordkirche\Ndk\Domain\Query\PageQuery\Nordkirche\Ndk\Domain\Query\SimpleQuery 查询。一些但不是所有存储库都有特定的查询类,以便应用特殊过滤器。这些类遵循以下命名方案

\Nordkirche\Ndk\Domain\Repository\*Repository -> \Nordkirche\Ndk\Domain\Query\*Query 

并且始终由 \Nordkirche\Ndk\Domain\Query\PageQuery 类派生。

查询中可用的存储库和过滤选项与 NAPI 文档中的端点和过滤选项等效。

示例查询

<?php
$api = new \Nordkirche\Ndk\Api($configuration);
$repository = $api->factory(\Nordkirche\Ndk\Domain\Repository\InstitutionRepository::class);
$result = $repository->get(new \Nordkirche\Ndk\Domain\Query\InstitutionQuery());
foreach ($result as $institution) {
    echo $institution->getLabel() . ' (' . $institution->getName() . ')' . PHP_EOL;
}

此示例包含两部分。一方面是初始化 API 和使用 factory() 方法创建存储库对象,另一方面是使用查询对象查询数据。

<?php
$api = new \Nordkirche\Ndk\Api($configuration);
$repository = $api->factory(\Nordkirche\Ndk\Domain\Repository\InstitutionRepository::class);

NDK 使用存储库,这些存储库代表 NAPI 的不同端点。在此示例中,我们使用了 InstitutionRepository 来查询机构。API 的 factory() 方法使用先前定义的配置实例化我们的存储库。

<?php
$result = $repository->get(new \Nordkirche\Ndk\Domain\Query\InstitutionQuery());
foreach ($result as $institution) {
    echo $institution->getLabel() . ' (' . $institution->getName() . ')' . PHP_EOL;
}

使用 get() 方法和查询对象查询机构列表。NDK 将这些打包到 \Nordkirche\Ndk\Service\Result 类的对象中,该对象除了以 \Nordkirche\Ndk\Domain\Model\Institution\Instituion 对象的形式提供资源对象外,还包含有关请求的额外元数据。

NAPI 按分页提供结果。因此,我们只能获得第一页。

元数据例如找到的所有对象的数量、当前页上的对象数量、可能的相关维度以进行进一步的过滤等。

此示例可以直接在 examples/2_simple_request.php 中执行。

查询

用户获取的页面、是否需要根据特定数据进行搜索或筛选等,都由一个查询对象决定。例如,在之前的示例中,使用了类 \Nordkirche\Ndk\Domain\Query\InstitutionQuery

由于大多数请求都是分页的,所以类 \Nordkirche\Ndk\Domain\Query\PageQuery 通常作为所有 *Query 类的父类。它可以用于所有查询,但如果没有特别指定,它将不提供如邮政编码之类的特殊筛选功能。

<?php
$query = new \Nordkirche\Ndk\Domain\Query\InstitutionQuery();
$query->setPageSize(30)->setPageNumber(2)->setZipCodes([24103]);
$result = $repository->get($query);

InstitutionQuery 这样的对象提供了各种选项来修改请求。除了定义所需页面 setPageNumber() 和每页条目数 setPageSize() 的常规选项外,我们还可以在机构和人员的情况下按邮政编码进行筛选。

建议查看 *Query 类的所有设置器。NAPI 的文档也提供了有关可能筛选器的信息。

资源对象

在 NDK 中,我们区分两种基于两个抽象类构建的模型类型。

\Nordkirche\Ndk\Domain\Model\AbstractModel
\Nordkirche\Ndk\Domain\Model\AbstractResourceObject

AbstractResourceObjectAbstractModels 的扩展,表示 NAPI 的资源对象。这些对象具有 ID、类型和其他资源的关联关系。它们通过存储库获取。

所有 AbstractModels 几乎都是资源的子对象,并组织资源对象的复杂数据。

属性

通常可以通过相应的 get*() 方法访问资源的属性。

但是,由于一些 get*() 方法是魔法方法,所以无法使用 method_exists() 检查属性是否可获取。为了允许动态检查和处理属性,可以使用 property_exists() 和通过 $object->property 直接访问属性。在此过程中,会考虑下一节中的 ResourcePlaceholderResolutionProxy 功能。

包含

NAPI 本身基于 JSON API 1.0 规范,因此它使用选项,即不直接返回与资源的关系,而是仅进行引用。

这导致相关资源对象不会自动包含在内,而是由 NDK 在需要时加载。以下以机构为例说明这种行为。

机构与其他资源对象有关联,例如它们的地址或类型。调用 getAddress() 方法将导致向 NAPI 发起另一个请求以获取机构的地址数据。

如果资源无法动态加载,则返回一个 ResourcePlaceholder 对象。该对象包含资源的生成标签以及可能的原因。

如果要以这种方式输出地址列表,则将为地址列表中的每个条目向 NAPI 发起另一个请求。

如果已知需要获取所有机构的地址,则可以将该关系包含在 NAPI 的响应中,从而避免不必要的请求。为此,将关系列表传递给查询对象。

<?php
use Nordkirche\Ndk\Domain\Model\Institution\Institution;

$query->setInclude([Institution::RELATION_ADDRESS, Institution::RELATION_INSTITUTION_TYPE]);

没有所有可能关系的列表,因为它们对资源对象是特定的。

所有包含关系的资源类都包含以 RELATION_ 开头的常量,这些常量指示可能的关系,可以使用它们构建包含数组。

从存储库的名称总是可以推断出相应的资源类。

\Nordkirche\Ndk\Domain\Repository\PersonRepository -> \Nordkirche\Ndk\Domain\Model\Person\Person

包含可以嵌套,以包含关系的关联关系。

<?php

use Nordkirche\Ndk\Domain\Model\Institution\Institution;

$query->setInclude([
    Institution::RELATION_ADDRESS,
    Institution::RELATION_PARENT_INSTITUTIONS => [
        Institution::RELATION_ADDRESS
    ]
]);

在上面的示例中,我们包含了请求的所有机构的地址,包括上级机构及其相应的地址。

人们可能会倾向于总是包含所有关系,以确保在所有情况下都不会向NAPI发送不必要的查询。需要注意的是,包含数据会使查询变慢。因此,应有意选择需要哪些关系进行哪些查询。

通过查看 examples/3_includes.php 示例,可以理解带和不带 setIncludes() 的查询之间的区别。

动态加载与包含

如果希望资源永远不会动态加载,则可以取消此功能的激活。

<?php
$configuration->setResolutionProxyDisabled(true);

此设置会导致未包含的关系返回 null。访问未包含的关系将被记录并可以输出。更多关于日志记录的内容请参阅日志记录部分。

资源对象的自身关系

有时,可能需要在数据库中为数据库中的对象创建自己的关系,例如为北德意志教会的人创建关系。为此,可以将NDK的资源对象转换为URI,这些URI可以保存。

可以通过将资源对象转换为字符串或调用 __toString() 方法来获得这些URI。

<?php
$uri = (string)$institution;

// oder

$uri = $institution->__toString();

生成的字符串格式为:napi://resource/type/1234。这些URI可以方便地解析。

<?php
$napi = $api->factory(\Nordkirche\Ndk\Service\NapiService::class);
$result = $napi->resolveUrl($uri);

还可以直接使用NDK解析整个URI列表并处理缺失的对象。

<?php
$uris = ['napi://resource/typeA/1234', 'napi://resource/typeB/4567', 'napi://resource/typeC/891011'];
$napi = $api->factory(\Nordkirche\Ndk\Service\NapiService::class);
foreach ($napi->resolveUrls($uris) as $result) {
    if ($result instanceof \Nordkirche\Ndk\Domain\Model\ResourcePlaceholder) {
        echo "Resource not found: " . $result->getLabel() . PHP_EOL;
    } else {
        echo "Found: " . $result->getName() . ' (' . $result->getId() . ')' . PHP_EOL;
    }
}

在此数组中可能包含人员、机构、事件等。

examples/5_napi_urls.php 示例演示了转换和解析的实践操作。

图片

资源对象可以包含图片。例如,一个机构有一个 getLogo() 标志,或者一个活动有一个描述性图片 getPicture()。图片由 \Nordkirche\Ndk\Domain\Model\File\Image 类的实例表示。

<?php
$repository = $api->factory(\Nordkirche\Ndk\Domain\Repository\InstitutionRepository::class);
$instituion = $repository->getById(1930);
$imageUrl = $instituion->getLogo()->render(150);
echo $imageUrl . PHP_EOL;

除了常见的图片和文件属性外,它还提供了 render($width, $height) 方法,以获得缩放版本的图片的URL。参数 $width$height 都是可选的。如果两个参数都指定,并且其中一个(或两个)带有后缀 c,则图片将被裁剪。

<?php
$imageUrl = $event->getPicture()->render('100c', '100c');

通过 getDetails() 方法可以获取更多图片和文件属性。包括图片说明、版权信息等。

NDK的扩展配置

可以在第一部分创建的配置对象 \Nordkirche\Ndk\Configuration 中添加更多选项,以调整NDK的行为。

日志记录

可以使用PSR-3兼容的记录器来截取NDK到NAPI的查询。

<?php
$logger = new \Monolog\Logger(
    'stdout',
    [new \Monolog\Handler\StreamHandler('php://stdout')]
);

$configuration->setLogger($logger);

请参阅 examples/5_logging.php 以了解使用Monolog的应用示例。

缓存

默认情况下,将HTTP查询到NAPI和内部数据临时存储在Doctrine ArrayCache中。

可以为应用中的特定方面设置PSR-6兼容的缓存,例如使用 doctrine/cache 中的不同驱动程序。

可以在 6_Caching.php 中查看和执行示例配置。

doctrine/cache 包本身提供了对多种后端的支持

对于所有可配置的缓存,建议使用内存缓存作为后端。例如 APCuRedisMemcache

HTTP缓存

<?php
$configuration->setHttpCacheProvider(new \Doctrine\Common\Cache\FilesystemCache('./cache/http'));

配置HTTP缓存中间件的后端。NAPI检查缓存中的查询是否包含新数据,并在必要时从自己的HTTP缓存中获取现有数据。

NDK特定缓存

<?php
$configuration->setReflectionCacheProvider(new \Doctrine\Common\Cache\FilesystemCache('./cache/reflection'));
$configuration->setDependencyInjectionCacheProvider(new \Doctrine\Common\Cache\FilesystemCache('./cache/di'));

这些内部缓存提高了NDK的总体执行速度。