yiisoft / data

Data providers

Home Page:https://www.yiiframework.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

DataReaderInterface::read() does not define whether to caching or not.

kamarton opened this issue · comments

What steps will reproduce the problem?

It also causes problems with usage and implementation.

public function read(): iterable;

For example, the PaginatorInterface cache is the result itself or not, because the data reader is already doing it.

Repeated reading may require:

  • caching: repeated read for get count, items and more.
  • not caching: reuse object, and watch change at any time.

What is the expected result?

specfy exactly

What do you get instead?

not specified

Q A
Version 3.0.x-dev
PHP version -
Operating system -

I suggests:

  • By default, be non-cache.
  • Extend interface with snapshot(): self method. This method would return a reader that, based on the data provided, saves and provide the current data now and in the future.

I can suggest:

  • Add a CachedDataReader decorator for the DataReaderInterface. A kind of universal caching layer
    class CachedReader implements DataReader {
        private $cache; 
        private DataReader $dataReader ; 
        __construct(DataReader $dataReader) {
            $this->dataReader = $dataReader;
        }
    
        function read() {
             // read from $this->dataReader, write to cache; on next call read from cache
        }
    }
  • We can also add the CachedDataReader interface, which will tell us that the DataReader itself implements the cache
  • I also liked the idea of ​​adding the IteratorAggregate interface to the DataReader.
    Wherein, the getIterator method does not write to the cache: realization, documentation

@roxblnfk sounds good. @kamarton what do you think?

@roxblnfk idea is basically like it.

I also liked the idea of ​​adding the IteratorAggregate interface to the DataReader.
Wherein, the getIterator method does not write to the cache: realization, documentation

Ok, if the iterator clearly defines that it represents the current state. I'm thinking here that the iterator can work directly from the data source (eg. fetch partially).

The only problem with this is that count and read are not handled together, eg.If the delay is significant (depend on data source change) between the two, the two together are inconsistent.

class CachedReader implements DataReader {
    private $cache; 
    private DataReader $dataReader ; 
    __construct(DataReader $dataReader) {
        $this->dataReader = $dataReader;
    }

    function read() {
         // read count write to cache; on next call read from cache
         // read from $this->dataReader, write to cache; on next call read from cache
    }

   function count() {
         // read count write to cache; on next call read from cache
         // read from $this->dataReader, write to cache; on next call read from cache
   }
}

It is also advisable to assume that the class is already inherited from CachedReader.

class CachedReader implements DataReader {

    private DataReader $dataReader ; 
    __construct(DataReader $dataReader) {
        $this->dataReader = $dataReader;
    }

    function read() {
      if($this->dataReader instanceof CachedReader) {
        return $this->dataReader->read();
      }
      // ...
    }

   function count() {
      if($this->dataReader instanceof CachedReader) {
        return $this->dataReader->count();
      }
      // ...
   }
}

I don't think it should be specified in the interface. In the discussion above about the caching decorator it is clearly visible: one implementation may require caching while another one may not.

About the cached decorator, I don't see an immediate use-case for it so closing the issue till it's requested for a real use-case.