如何在 silverstripe 4 中使用缓存实现存储库模式?

How can I achieve repository pattern with caching in silverstripe 4?

我有一个第三方 API,我用它来获取用户及其详细信息。如何在 silverstripe 4 中使用缓存实现存储库模式?

我有一个名为 UserRepositoryInterface 的接口

interface UserRepositoryInterface
{
   public function getAll();
}

UserRepository,与 API 交互以获取用户及其详细信息

class UserRepository implements UserRepositoryInterface
{
   protected $client;

   public function __construct(Client $client)
   {
      $this->client = $client;
   }

   public function getAll()
   {
      return $this->client->fetchUsers();
   }
}

我知道我们需要一个 CachedUserRepository,如果存在则从缓存中获取用户,否则从 API 目录中获取。我将如何继续实施它?

试图在 silverstripe 4

中实现类似的东西 https://laracasts.com/discuss/channels/laravel/repository-pattern-with-caching-laravel?#reply=398497

如果您不想将 UserRepositoryCachedUserRepository 实现分开,您只需将缓存添加到 UserRepository:

use Psr\SimpleCache\CacheInterface;

class UserRepository implements UserRepositoryInterface
{
    protected $client;

    protected $cache;

    private static $dependencies = [
        'Cache' => '%$' . CacheInterface::class . '.userrepository',
    ];

    public function __construct(Client $client)
    {
        $this->client = $client;
    }

    public function getAll()
    {
        if (!$this->cache->get('fetchUsers')) {
            $users = $this->client->fetchUsers();
            $this->cache->set('fetchUsers', $users);
        }
        return $this->cache->get('fetchUsers');
    }

    public function setCache(CacheInterface $cache)
    {
        $this->cache = $cache;
        return $this;
    }
}

以及一些用于注册缓存的 YAML 配置:

SilverStripe\Core\Injector\Injector:
  Psr\SimpleCache\CacheInterface.userrepository:
    factory: SilverStripe\Core\Cache\CacheFactory
    constructor:
      namespace: userrepository

如果你想像你链接到的文章中那样分离实现,你可以做一些类似于文章中的事情,但你需要定义你自己的与 UserRepository 因为 SilverStripe 没有这种开箱即用的 API。

例如,像这样的东西:

class CachedUserRepository implements UserRepositoryInterface
{
    protected $repository;

    protected $cache;

    private static $dependencies = [
        'Cache' => '%$' . CacheInterface::class . '.userrepository',
    ];

    public function __construct(UserRepository $repository)
    {
        $this->repository = $repository;
    }

    public function getAll()
    {
        if (!$this->cache->get('fetchUsers')) {
            $users = $this->repository->getAll();
            $this->cache->set('fetchUsers', $users);
        }
        return $this->cache->get('fetchUsers');
    }

    public function setCache(CacheInterface $cache)
    {
        $this->cache = $cache;
        return $this;
    }
}

我猜你会像这样实例化它:

$repository = Injector::inst()->create(CachedUserRepository::class, [
    Injector::inst()->get(UserRepository::class),
]);

请注意,使用 Injector 实例化您的 classes 非常重要,以便在构建后通过 $dependencies 注册依赖注入。

为了与 SilverStripe 中的依赖注入模式保持一致,您可能还想以相同的方式将 Client 注入 UserRepository,以及将 UserRepository 注入CachedUserRepository 以同样的方式(构造函数已删除但未在这些示例中显示。

用户资料库:

private static $dependencies = [
    'Client' => '%$' . Client::class,
];

public function setClient(Client $client)
{
    $this->client = $client;
    return $this;
}

CachedUserRepository:

private static $dependencies = [
    'Cache' => '%$' . CacheInterface::class . '.userrepository',
    'Repository' => '%$' . UserRepository::class,
];

public function setRepository(UserRepository $repository)
{
    $this->repository = $repository;
    return $this;
}

现在 Injector 将为您处理所有依赖项注入,因此您的实现将如下所示:

$repository = Injector::inst()->get(CachedUserRepository::class);

您可以更进一步(这是 SilverStripe 4 中的一种常见模式)并为您的接口定义一个具体的实现,因此该实现不需要知道将使用哪个 class :

# File: app/_config/repositories.yml
SilverStripe\Core\Injector\Injector:
  UserRepositoryInterface:
    # Define the repository you want by default
    class: CachedUserRepository

现在您可以像这样获取您的存储库(默认缓存):

$repository = Injector::inst()->get(UserRepositoryInterface::class);