Skip to content

Commit

Permalink
Merge pull request #90 from bburnichon/ticket_86_stream_writer
Browse files Browse the repository at this point in the history
Add An Abstract StreamWriter
  • Loading branch information
Baachi committed Jul 22, 2014
2 parents 72792d8 + e70b6a2 commit 0fe6fc1
Show file tree
Hide file tree
Showing 8 changed files with 554 additions and 37 deletions.
49 changes: 47 additions & 2 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 @@ -374,8 +376,8 @@ Writes CSV files:
```php
use Ddeboer\DataImport\Writer\CsvWriter;

$file = new \SplFileObject('output.csv', 'w');
$writer = new CsvWriter($file);
$writer = new CsvWriter();
$writer->setStream(fopen('output.csv', 'w'));

// Write column headers:
$writer->writeItem(array('first', 'last'));
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->setCloseStreamOnFinish(false);

$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
106 changes: 106 additions & 0 deletions src/Ddeboer/DataImport/Writer/AbstractStreamWriter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

namespace Ddeboer\DataImport\Writer;

/**
* Base class to write into streams
*
* @author Benoît Burnichon <bburnichon@gmail.com>
*/
abstract class AbstractStreamWriter implements WriterInterface
{
private $stream;
private $closeStreamOnFinish = true;

/**
* Constructor
*
* @param resource $stream
*/
public function __construct($stream = null)
{
if (null !== $stream) {
$this->setStream($stream);
}
}

/**
* Set Stream Resource
*
* @param $stream
* @throws \InvalidArgumentException
* @return $this
*/
public function setStream($stream)
{
if (! is_resource($stream) || ! 'stream' == get_resource_type($stream)) {
throw new \InvalidArgumentException(sprintf(
'Expects argument to be a stream resource, got %s',
is_resource($stream) ? get_resource_type($stream) : gettype($stream)
));
}

$this->stream = $stream;

return $this;
}

/**
* Get underlying stream resource
*
* @return resource
*/
public function getStream()
{
if (null === $this->stream) {
$this->setStream(fopen('php://temp', 'rb+'));
$this->setCloseStreamOnFinish(false);
}

return $this->stream;
}

/**
* @inheritdoc
*/
public function prepare()
{
return $this;
}

/**
* @inheritdoc
*/
public function finish()
{
if (is_resource($this->stream) && $this->getCloseStreamOnFinish()) {
fclose($this->stream);
}

return $this;
}

/**
* Should underlying stream be closed on finish?
*
* @param bool $closeStreamOnFinish
*
* @return bool
*/
public function setCloseStreamOnFinish($closeStreamOnFinish = true)
{
$this->closeStreamOnFinish = (bool) $closeStreamOnFinish;

return $this;
}

/**
* Is Stream closed on finish?
*
* @return bool
*/
public function getCloseStreamOnFinish()
{
return $this->closeStreamOnFinish;
}
}
27 changes: 8 additions & 19 deletions src/Ddeboer/DataImport/Writer/CsvWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@

/**
* Writes to a CSV file
*
*/
class CsvWriter extends AbstractWriter
class CsvWriter extends AbstractStreamWriter
{
private $delimiter = ';';
private $enclosure = '"';

/**
* Constructor
*
* @param \SplFileObject $file CSV file
* @param string $mode See http://php.net/manual/en/function.fopen.php
* @param string $delimiter The delimiter
* @param string $enclosure The enclosure
* @param string $delimiter The delimiter
* @param string $enclosure The enclosure
* @param resource $stream
*/
public function __construct(\SplFileObject $file, $mode = 'w', $delimiter = ';', $enclosure = '"')
public function __construct($delimiter = ';', $enclosure = '"', $stream = null)
{
$this->fp = fopen($file->getPathname(), $mode);
parent::__construct($stream);

$this->delimiter = $delimiter;
$this->enclosure = $enclosure;
}
Expand All @@ -31,17 +30,7 @@ public function __construct(\SplFileObject $file, $mode = 'w', $delimiter = ';',
*/
public function writeItem(array $item)
{
fputcsv($this->fp, $item, $this->delimiter, $this->enclosure);

return $this;
}

/**
* {@inheritdoc}
*/
public function finish()
{
fclose($this->fp);
fputcsv($this->getStream(), $item, $this->delimiter, $this->enclosure);

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

namespace Ddeboer\DataImport\Writer;

/**
* Class allowing multiple writers to write in same stream
*
* @author Benoît Burnichon <bburnichon@gmail.com>
*/
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->setCloseStreamOnFinish(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;
}
}
Loading

0 comments on commit 0fe6fc1

Please sign in to comment.