Skip to content

Commit

Permalink
Update Stream Filtering detection mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Mar 18, 2021
1 parent c16f707 commit b518855
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 32 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ All Notable changes to `Csv` will be documented in this file
- `League\Csv\Info::fetchBOMSequence` to replace the namespace function `bom_match`
- `League\Csv\AbstractCsv::toString` to replace `League\Csv\AbstractCsv::getContent` and `League\Csv\AbstractCsv::__toString`
- `League\Csv\XMLConverter::create` to replace `League\Csv\XMLConverter::__construct`
- `League\Csv\HTMLConverter::__create` to replace `League\Csv\HTMLConverter::__construct`
- `League\Csv\HTMLConverter::create` to replace `League\Csv\HTMLConverter::__construct`
- `League\Csv\AbstractCsv::supportsStreamFilterOnRead` and `League\Csv\AbstractCsv::supportsStreamFilterOnWrite` to replace `League\Csv\AbstractCsv::supportsStreamFilter` and `League\Csv\AbstractCsv::getStreamFilterMode`

### Deprecated

- `League\Csv\delimiter_detect` use `League\Csv\Info::getDelimiterStats`
- `League\Csv\bom_match` use `League\Csv\Info::fetchBOMSequence`
- `League\Csv\AbstractCsv::getContent` use `League\Csv\AbstractCsv::toString`
- `League\Csv\AbstractCsv::getStreamFilterMode` use `League\Csv\AbstractCsv::supportsStreamFilterOnRead` or `League\Csv\AbstractCsv::supportsStreamFilterOnWrite`
- `League\Csv\AbstractCsv::supportsStreamFilter` use `League\Csv\AbstractCsv::supportsStreamFilterOnRead` or `League\Csv\AbstractCsv::supportsStreamFilterOnWrite`
- Calling exceptions constructor, use named constructors instead.
- `League\Csv\XMLConverter::__construct` use `League\Csv\XMLConverter::create`
- `League\Csv\HTMLConverter::__construct` use `League\Csv\HTMLConverter::create`
Expand All @@ -29,10 +32,13 @@ All Notable changes to `Csv` will be documented in this file
- Move tests into the `src` directory
- Fixed encoder method resolver implementation
- all classes marked as `@internal` are now final
- `League\Csv\AbstractCsv::STREAM_FILTER_MODE` constant replaces `League\Csv\AbstractCsv::$stream_filter_mode`

### Removed

- None
- `League\Csv\AbstractCsv::$stream_filter_mode`


## 9.6.2 - 2020-12-10

Expand Down
5 changes: 2 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
}
},
"scripts": {
"phpcs": "php-cs-fixer fix -v --diff --dry-run --allow-risky=yes --ansi",
"phpcs": "php-cs-fixer fix -vvv --diff --dry-run --allow-risky=yes --ansi",
"phpcs:fix": "php-cs-fixer fix -vvv --allow-risky=yes --ansi",
"phpstan": "phpstan analyse -l max -c phpstan.neon src --ansi --memory-limit=192M",
"phpunit": "phpunit --coverage-text",
"test": [
Expand All @@ -63,8 +64,6 @@
"scripts-descriptions": {
"phpcs": "Runs coding style test suite",
"phpstan": "Runs complete codebase static analysis",
"phpstan-src": "Runs source code static analysis",
"phpstan-test": "Runs test suite static analysis",
"phpunit": "Runs unit and functional testing",
"test": "Runs full test suite"
},
Expand Down
29 changes: 28 additions & 1 deletion docs/9.0/connections/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,33 @@ To ease performing operations on the CSV document as it is being read from or wr

## Detecting stream filter support

<p class="message-notice">Since version <code>9.7.0</code> the detection mechanism is simplified</p>

The following methods are added:

- `supportsStreamFilterOnRead` tells whether the stream filter API on reading mode is supported by the CSV object;
- `supportsStreamFilterOnWrite` tells whether the stream filter API on writing mode is supported by the CSV object;

~~~php
public AbstractCsv::supportsStreamFilterOnRead(void): bool
public AbstractCsv::supportsStreamFilterOnWrite(void): bool
~~~

~~~php
use League\Csv\Reader;
use League\Csv\Writer;

$reader = Reader::createFromPath('/path/to/my/file.csv', 'r');
$reader->supportsStreamFilterOnRead(); //return true
$reader->supportsStreamFilterOnWrite(); //return false

$writer = Writer::createFromFileObject(new SplTempFileObject());
$writer->supportsStreamFilterOnRead(); // returns false, the API can not be used
$writer->supportsStreamFilterOnWrite(); // returns false, the API can not be used
~~~

<p class="message-notice">The following methods still work but are deprecated since version <code>9.7.0</code></p>

~~~php
public AbstractCsv::supportsStreamFilter(void): bool
public AbstractCsv::getStreamFilterMode(void): int
Expand Down Expand Up @@ -74,7 +101,7 @@ stream_filter_register('convert.utf8decode', Transcode::class);
// 'MyLib\Transcode' is a class that extends PHP's php_user_filter class

$reader = Reader::createFromPath('/path/to/my/chinese.csv', 'r');
if ($reader->supportsStreamFilter()) {
if ($reader->supportsStreamFilterOnRead()) {
$reader->addStreamFilter('convert.utf8decode');
$reader->addStreamFilter('string.toupper');
}
Expand Down
45 changes: 34 additions & 11 deletions src/AbstractCsv.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,7 @@
*/
abstract class AbstractCsv implements ByteSequence
{
/**
* The stream filter mode (read or write).
*
* @var int
*/
protected $stream_filter_mode;
protected const STREAM_FILTER_MODE = STREAM_FILTER_READ;

/**
* collection of stream filters.
Expand Down Expand Up @@ -111,9 +106,7 @@ protected function __construct($document)
/**
* Reset dynamic object properties to improve performance.
*/
protected function resetProperties(): void
{
}
abstract protected function resetProperties(): void;

/**
* {@inheritdoc}
Expand Down Expand Up @@ -232,21 +225,51 @@ public function getInputBOM(): string
}

/**
* DEPRECATION WARNING! This method will be removed in the next major point release.
*
* @deprecated since version 9.7.0
* @see AbstractCsv::supportsStreamFilterOnRead
* @see AbstractCsv::supportsStreamFilterOnWrite
*
* Returns the stream filter mode.
*/
public function getStreamFilterMode(): int
{
return $this->stream_filter_mode;
return static::STREAM_FILTER_MODE;
}

/**
* DEPRECATION WARNING! This method will be removed in the next major point release.
*
* @deprecated since version 9.7.0
* @see AbstractCsv::supportsStreamFilterOnRead
* @see AbstractCsv::supportsStreamFilterOnWrite
*
* Tells whether the stream filter capabilities can be used.
*/
public function supportsStreamFilter(): bool
{
return $this->document instanceof Stream;
}

/**
* Tells whether the stream filter read capabilities can be used.
*/
public function supportsStreamFilterOnRead(): bool
{
return $this->document instanceof Stream
&& ((static::STREAM_FILTER_MODE & STREAM_FILTER_READ) === STREAM_FILTER_READ);
}

/**
* Tells whether the stream filter write capabilities can be used.
*/
public function supportsStreamFilterOnWrite(): bool
{
return $this->document instanceof Stream
&& ((static::STREAM_FILTER_MODE & STREAM_FILTER_WRITE) === STREAM_FILTER_WRITE);
}

/**
* Tell whether the specify stream filter is attach to the current stream.
*/
Expand Down Expand Up @@ -510,7 +533,7 @@ public function addStreamFilter(string $filtername, $params = null): self
throw UnavailableFeature::dueToUnsupportedStreamFilterApi(get_class($this->document));
}

$this->document->appendFilter($filtername, $this->stream_filter_mode, $params);
$this->document->appendFilter($filtername, self::STREAM_FILTER_MODE, $params);
$this->stream_filters[$filtername] = true;
$this->resetProperties();
$this->input_bom = null;
Expand Down
53 changes: 49 additions & 4 deletions src/AbstractCsvTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,55 @@ public function testChunk(): void
self::assertSame($expected, $res);
}

public function testStreamFilterMode(): void
{
self::assertSame(STREAM_FILTER_READ, Reader::createFromString('')->getStreamFilterMode());
self::assertSame(STREAM_FILTER_WRITE, Writer::createFromString('')->getStreamFilterMode());
/**
* @dataProvider provideCsvFilterTestingData
*/
public function testStreamFilterMode(
AbstractCsv $csv,
int $filterMode,
bool $supportFilter,
bool $useFilterRead,
bool $useFilterWrite
): void {
self::assertSame($filterMode, $csv->getStreamFilterMode());
self::assertSame($supportFilter, $csv->supportsStreamFilter());
self::assertSame($useFilterRead, $csv->supportsStreamFilterOnRead());
self::assertSame($useFilterWrite, $csv->supportsStreamFilterOnWrite());
}

public function provideCsvFilterTestingData(): iterable
{
yield 'Reader with stream capability' => [
'csv' => Reader::createFromString(),
'filterMode' => STREAM_FILTER_READ,
'supportsFilter' => true,
'useFilterRead' => true,
'useFilterWrite' => false,
];

yield 'Reader without stream capability' => [
'csv' => Reader::createFromFileObject(new SplTempFileObject()),
'filterMode' => STREAM_FILTER_READ,
'supportsFilter' => false,
'useFilterRead' => false,
'useFilterWrite' => false,
];

yield 'Writer with stream capability' => [
'csv' => Writer::createFromString(),
'filterMode' => STREAM_FILTER_WRITE,
'supportsFilter' => true,
'useFilterRead' => false,
'useFilterWrite' => true,
];

yield 'Writer without stream capability' => [
'csv' => Writer::createFromFileObject(new SplTempFileObject()),
'filterMode' => STREAM_FILTER_WRITE,
'supportsFilter' => false,
'useFilterRead' => false,
'useFilterWrite' => false,
];
}

/**
Expand Down
8 changes: 2 additions & 6 deletions src/Reader.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
*/
class Reader extends AbstractCsv implements TabularDataReader, JsonSerializable
{
protected const STREAM_FILTER_MODE = STREAM_FILTER_READ;

/**
* header offset.
*
Expand All @@ -60,11 +62,6 @@ class Reader extends AbstractCsv implements TabularDataReader, JsonSerializable
*/
protected $nb_records = -1;

/**
* {@inheritdoc}
*/
protected $stream_filter_mode = STREAM_FILTER_READ;

/**
* @var bool
*/
Expand All @@ -83,7 +80,6 @@ public static function createFromPath(string $path, string $open_mode = 'r', $co
*/
protected function resetProperties(): void
{
parent::resetProperties();
$this->nb_records = -1;
$this->header = [];
}
Expand Down
8 changes: 2 additions & 6 deletions src/Writer.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
*/
class Writer extends AbstractCsv
{
protected const STREAM_FILTER_MODE = STREAM_FILTER_WRITE;

/**
* callable collection to format the record before insertion.
*
Expand Down Expand Up @@ -63,11 +65,6 @@ class Writer extends AbstractCsv
*/
protected $flush_threshold;

/**
* {@inheritdoc}
*/
protected $stream_filter_mode = STREAM_FILTER_WRITE;

/**
* Regular expression used to detect if RFC4180 formatting is necessary.
*
Expand All @@ -87,7 +84,6 @@ class Writer extends AbstractCsv
*/
protected function resetProperties(): void
{
parent::resetProperties();
$characters = preg_quote($this->delimiter, '/').'|'.preg_quote($this->enclosure, '/');
$this->rfc4180_regexp = '/[\s|'.$characters.']/x';
$this->rfc4180_enclosure = $this->enclosure.$this->enclosure;
Expand Down

0 comments on commit b518855

Please sign in to comment.