【问题标题】:How can I achieve repository pattern with caching in silverstripe 4?如何在 silverstripe 4 中通过缓存实现存储库模式?
【发布时间】:2019-01-13 18:56:01
【问题描述】:

我有一个第 3 方 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 的目标

【问题讨论】:

    标签: php silverstripe silverstripe-4


    【解决方案1】:

    如果您不想分离您的 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 实例化您的类非常重要,以便在构造后注册通过 $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 中的一种常见模式)并为您的接口定义一个具体的实现,因此该实现不需要知道要使用哪个类:

    # 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-30
      • 1970-01-01
      相关资源
      最近更新 更多