Skip to content

Commit

Permalink
Add StreamMergeWriter, some documentation and tweak AbstractStreamWriter
Browse files Browse the repository at this point in the history
Signed-off-by: Benoît Burnichon <bburnichon@gmail.com>
  • Loading branch information
bburnichon committed Jul 5, 2014
1 parent 054e0e0 commit 539cd82
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 0 deletions.
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Documentation
- [ExcelWriter](#excelwriter)
- [ConsoleProgressWriter](#consoleprogresswriter)
- [CallbackWriter](#callbackwriter)
- [AbstractStreamWriter](#abstractstreamwriter)
- [StreamMergeWriter](#streammergewriter)
- [Create a writer](#create-a-writer)
* [Filters](#filters)
- [CallbackFilter](#callbackfilter)
Expand Down Expand Up @@ -492,6 +494,49 @@ $workflow->addWriter(new CallbackWriter(function ($row) use ($storage) {
$storage->store($row);
}));
```
#### AbstractStreamWriter

Instead of implementing your own writer from scratch, you can use AbstractStreamWriter as a basis,
implemented the ```writeItem``` method and you're done:

```php
use Ddeboer\DataImport\Writer\AbstractStreamWriter;

class MyStreamWriter extends AbstractStreamWriter
{
public function writeItem(array $item)
{
fputs($this->getStream(), implode(',', $item));
}
}

$writer = new MyStreamWriter(fopen('php://temp', 'r+'));
$writer->closeStreamOnFinish();

$workflow->addWriter(new MyStreamWriter());
$workflow->process();

$stream = $writer->getStream();
rewind($stream);

echo stream_get_contents($stream);
```

#### StreamMergeWriter

Suppose you have 2 stream writers handling fields differently according to one of the fields.
You should then use ```StreamMergeWriter``` to call the appropriate Writer for you.

The default field name is ```discr``` but could be changed with the ```setDiscriminantField()``` method.

```php
use Ddeboer\DataImport\Writer\StreamMergeWriter;

$writer = new StreamMergeWriter();

$writer->addWriter('first writer', new MyStreamWriter());
$writer->addWriter('second writer', new MyStreamWriter());
```

#### Create a writer

Expand Down
1 change: 1 addition & 0 deletions src/Ddeboer/DataImport/Writer/AbstractStreamWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function getStream()
{
if (null === $this->stream) {
$this->setStream(fopen('php://temp', 'r+'));
$this->closeStreamOnFinish(false);
}

return $this->stream;
Expand Down
121 changes: 121 additions & 0 deletions src/Ddeboer/DataImport/Writer/StreamMergeWriter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

namespace Ddeboer\DataImport\Writer;

class StreamMergeWriter extends AbstractStreamWriter
{
/** @var string */
private $discriminantField = 'discr';
/** @var AbstractStreamWriter[] */
private $writers = array();

/**
* Set Discriminant field
*
* @param string $discriminantField
* @return $this
*/
public function setDiscriminantField($discriminantField)
{
$this->discriminantField = (string) $discriminantField;
return $this;
}

/**
* Get Discriminant Field
*
* @return string
*/
public function getDiscriminantField()
{
return $this->discriminantField;
}

/**
* @inheritdoc
*/
public function writeItem(array $item)
{
if ((isset($item[$this->discriminantField])
|| array_key_exists($this->discriminantField, $item))
&& $this->hasStreamWriter($key = $item[$this->discriminantField])
) {
$writer = $this->getStreamWriter($key);

$writer->writeItem($item);
}

return $this;
}

/**
* Set Stream writers
* @param AbstractStreamWriter[] $writers
*
* @return $this
*/
public function setStreamWriters(array $writers)
{
foreach ($writers as $key => $writer) {
$this->setStreamWriter($key, $writer);
}

return $this;
}

/**
* @param string $key
* @param AbstractStreamWriter $writer
* @return $this
*/
public function setStreamWriter($key, AbstractStreamWriter $writer)
{
$writer->setStream($this->getStream());
$writer->closeStreamOnFinish(false);
$this->writers[$key] = $writer;

return $this;
}

/**
* Get a previously registered Writer
*
* @param string $key
* @return AbstractStreamWriter
*/
public function getStreamWriter($key)
{
return $this->writers[$key];
}

/**
* Get list of registered Writers
*
* @return AbstractStreamWriter[]
*/
public function getStreamWriters()
{
return $this->writers;
}

/**
* Is a writer registered for key?
*
* @param string $key
* @return bool
*/
public function hasStreamWriter($key)
{
return isset($this->writers[$key]);
}

public function setStream($stream)
{
parent::setStream($stream);
foreach ($this->getStreamWriters() as $writer) {
$writer->setStream($stream);
}

return $this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ public function testCloseOnFinishIsInhibitable()
$this->assertTrue($this->writer->closeStreamOnFinish());
}

public function testCloseOnFinishIsFalseForAutoOpenedStreams()
{
$this->writer->closeStreamOnFinish(true);
$this->writer->getStream();
$this->assertFalse($this->writer->closeStreamOnFinish());
}

public function testFinishCloseStreamAccordingToCloseOnFinishState()
{
$stream = $this->getStream();
Expand Down
141 changes: 141 additions & 0 deletions tests/Ddeboer/DataImport/Tests/Writer/StreamMergeWriterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

namespace Ddeboer\DataImport\Tests\Writer;

use Ddeboer\DataImport\Writer\StreamMergeWriter;

class StreamMergeWriterTest extends AbstractStreamWriterTest
{
/** @var StreamMergeWriter */
protected $writer;

protected function setUp()
{
parent::setUp();

$this->writer = new StreamMergeWriter();
}

public function testItIsInstantiable()
{
$this->assertInstanceOf('Ddeboer\DataImport\Writer\StreamMergeWriter', $this->writer);
}

public function testItIsAStreamWriter()
{
$this->assertInstanceOf('Ddeboer\DataImport\Writer\AbstractStreamWriter', $this->writer);
}

public function testDiscriminantField()
{
$this->assertSame($this->writer, $this->writer->setDiscriminantField('foo'));
$this->assertSame('foo', $this->writer->getDiscriminantField());
}

public function testDiscriminantFieldDefaultsToDiscr()
{
$this->assertSame('discr', $this->writer->getDiscriminantField());
}

public function testSetStreamWriterForSpecificDiscrValue()
{
$fooWriter = $this->getMockBuilder('Ddeboer\DataImport\Writer\AbstractStreamWriter')
->setMethods(array('setStream'))
->getMockForAbstractClass();

$this->writer->setStream($stream = $this->getStream());
$fooWriter
->expects($this->once())
->method('setStream')
->with($stream)
->will($this->returnSelf());

$this->assertSame($this->writer, $this->writer->setStreamWriter('foo', $fooWriter));
$this->assertSame($fooWriter, $this->writer->getStreamWriter('foo'));
}

public function testHasStreamWriter()
{
$fooWriter = $this->getMockBuilder('Ddeboer\DataImport\Writer\AbstractStreamWriter')
->getMockForAbstractClass();

$this->assertFalse($this->writer->hasStreamWriter('foo', 'no foo stream writer should be registered'));
$this->writer->setStreamWriter('foo', $fooWriter);
$this->assertTrue($this->writer->hasStreamWriter('foo'), 'foo stream writer should be registered');
}

public function testStreamWriters()
{
$fooWriter = $this->getMockBuilder('Ddeboer\DataImport\Writer\AbstractStreamWriter')
->getMockForAbstractClass();
$barWriter = $this->getMockBuilder('Ddeboer\DataImport\Writer\AbstractStreamWriter')
->getMockForAbstractClass();
$writers = array(
'foo' => $fooWriter,
'bar' => $barWriter,
);

$this->assertSame($this->writer, $this->writer->setStreamWriters($writers));
$this->assertSame($writers, $this->writer->getStreamWriters());
}

public function testWriteItem()
{
$fooWriter = $this->getMockBuilder('Ddeboer\DataImport\Writer\AbstractStreamWriter')
->getMockForAbstractClass();
$barWriter = $this->getMockBuilder('Ddeboer\DataImport\Writer\AbstractStreamWriter')
->getMockForAbstractClass();
$writers = array(
'foo' => $fooWriter,
'bar' => $barWriter,
);
$this->writer->setStreamWriters($writers);
$this->writer->setDiscriminantField('foo');

$barItem = array('foo' => 'bar');
$fooWriter->expects($this->never())
->method('writeItem');
$barWriter->expects($this->once())
->method('writeItem')
->with($barItem)
->will($this->returnSelf());

$this->assertSame($this->writer, $this->writer->writeItem($barItem));
}

public function testSetStream()
{
$fooWriter = $this->getMockBuilder('Ddeboer\DataImport\Writer\AbstractStreamWriter')
->getMockForAbstractClass();
$barWriter = $this->getMockBuilder('Ddeboer\DataImport\Writer\AbstractStreamWriter')
->getMockForAbstractClass();
$writers = array(
'foo' => $fooWriter,
'bar' => $barWriter,
);
$stream = $this->writer->getStream();
$this->writer->setStreamWriters($writers);

$this->assertSame($stream, $fooWriter->getStream());
$this->assertSame($stream, $barWriter->getStream());

$this->assertSame($this->writer, $this->writer->setStream($stream = $this->getStream()));

$this->assertSame($stream, $fooWriter->getStream());
$this->assertSame($stream, $barWriter->getStream());
}

public function testSetWriterShouldInhibitStreamClose()
{
$fooWriter = $this->getMockBuilder('Ddeboer\DataImport\Writer\AbstractStreamWriter')
->setMethods(array('closeStreamOnFinish'))
->getMockForAbstractClass();

$fooWriter
->expects($this->once())
->method('closeStreamOnFinish')->with(false)
->will($this->returnArgument(0));

$this->writer->setStreamWriter('foo', $fooWriter);
}
}

0 comments on commit 539cd82

Please sign in to comment.