如何在Silverstripe 4中通过缓存实现存储库模式?

时间:2019-01-13 18:56:01

标签: php silverstripe 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的功能

1 个答案:

答案 0 :(得分:2)

如果您不想分离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

如果您想要以类似于所链接文章中的方式来分离实现,则可以执行与文章中类似的操作,但是您需要定义自己的与{{1}进行交互的方法},因为SilverStripe没有现成的API。

例如,如下所示:

UserRepository

我想您可以这样实例化它:

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;
    }
}

请注意,使用Injector实例化您的类很重要,以便在构造后通过$repository = Injector::inst()->create(CachedUserRepository::class, [ Injector::inst()->get(UserRepository::class), ]); 注册依赖项注入。

为了与SilverStripe中的依赖项注入模式保持一致,您可能还希望以相同的方式将$dependencies注入到Client中,以及将UserRepository注入到{{ 1}}的用法相同(删除了构造函数,但这些示例中未显示。

UserRepository:

UserRepository

CachedUserRepository:

CachedUserRepository

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

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

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

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

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

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

现在您可以像这样获取存储库(默认情况下为缓存):

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