Skip to content

Commit

Permalink
Merge pull request #71 from warmans/feature/pdo-writer
Browse files Browse the repository at this point in the history
Added PdoWriter
  • Loading branch information
ddeboer committed May 29, 2014
2 parents 30d5f5e + f043eef commit b96417d
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 9 deletions.
33 changes: 24 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Ddeboer Data Import library
===========================
[![Build Status](https://travis-ci.org/ddeboer/data-import.png?branch=master)](https://travis-ci.org/ddeboer/data-import)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/ddeboer/data-import/badges/quality-score.png?s=41129c80140adc6931288c9df15fb87ec6ea6f8a)](https://scrutinizer-ci.com/g/ddeboer/data-import/)
[![Code Coverage](https://scrutinizer-ci.com/g/ddeboer/data-import/badges/coverage.png?s=724267091a6d02f83b6c435a431e71d467b361f8)](https://scrutinizer-ci.com/g/ddeboer/data-import/)
[![Build Status](https://travis-ci.org/ddeboer/data-import.png?branch=master)](https://travis-ci.org/ddeboer/data-import)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/ddeboer/data-import/badges/quality-score.png?s=41129c80140adc6931288c9df15fb87ec6ea6f8a)](https://scrutinizer-ci.com/g/ddeboer/data-import/)
[![Code Coverage](https://scrutinizer-ci.com/g/ddeboer/data-import/badges/coverage.png?s=724267091a6d02f83b6c435a431e71d467b361f8)](https://scrutinizer-ci.com/g/ddeboer/data-import/)
[![Latest Stable Version](https://poser.pugx.org/ddeboer/data-import/v/stable.png)](https://packagist.org/packages/ddeboer/data-import)

Introduction
Expand Down Expand Up @@ -36,6 +36,7 @@ Documentation
- [ArrayWriter](#arraywriter)
- [CsvWriter](#csvwriter)
- [DoctrineWriter](#doctrinewriter)
- [PdoWriter](#pdowriter)
- [ExcelWriter](#excelwriter)
- [ConsoleProgressWriter](#consoleprogresswriter)
- [CallbackWriter](#callbackwriter)
Expand All @@ -59,7 +60,7 @@ Documentation
- [Import CSV file and write to database](#import-csv-file-and-write-to-database)
- [Export to CSV file](#export-to-csv-file)
* [Running the tests](#running-the-tests)
* [License](#license)
* [License](#license)

Installation
------------
Expand Down Expand Up @@ -316,6 +317,20 @@ $writer
->finish();
```

#### PdoWriter

Use the PDO writer for importing data into a relational database (such as
MySQL, SQLite or MS SQL) without using Doctrine.

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

$pdo = new \PDO('sqlite::memory:');
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

$writer = new PdoWriter($pdo, 'my_table');
```

#### ExcelWriter

Writes data to an Excel file. It requires the PHPExcel package:
Expand Down Expand Up @@ -359,7 +374,7 @@ $writer = new ExcelWriter($file, 'Old sheet');

#### ConsoleProgressWriter

This writer displays import progress when you start the workflow from the
This writer displays import progress when you start the workflow from the
command-line. It requires Symfony’s Console component:

```bash
Expand Down Expand Up @@ -397,12 +412,12 @@ Build your own writer by implementing the

### Filters

A filter decides whether data input is accepted into the import process.
A filter decides whether data input is accepted into the import process.

#### CallbackFilter

The CallbackFilter wraps your callback function that determines whether
data should be accepted. The data input is accepted only if the function
data should be accepted. The data input is accepted only if the function
returns `true`.

```php
Expand Down Expand Up @@ -526,7 +541,7 @@ Implement `ItemConverterInterface` to create your own item converter:
```php
use Ddeboer\DataImport\ItemConverter\ItemConverterInterface;

class MyItemConverter implements ItemConverterInterface
class MyItemConverter implements ItemConverterInterface
{
public function convert($item)
{
Expand All @@ -548,7 +563,7 @@ $converter = new CallbackItemConverter(function ($item) use ($translator) {
foreach ($item as $key => $value) {
$item[$key] = $translator->translate($value);
}

return $row;
});
```
Expand Down
7 changes: 7 additions & 0 deletions src/Ddeboer/DataImport/Exception/WriterException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Ddeboer\DataImport\Exception;

class WriterException extends \Exception implements ExceptionInterface
{
}
91 changes: 91 additions & 0 deletions src/Ddeboer/DataImport/Writer/PdoWriter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace Ddeboer\DataImport\Writer;

use \Ddeboer\DataImport\Exception\WriterException;

/**
* Class PdoWriter
*
* Write data into a specific database table using a PDO instance.
*
* IMPORTANT: If your PDO instance does not have ERRMODE_EXCEPTION any write failure will be silent or logged to
* stderr only. It is strongly recomended you enable Exceptions with:
*
* $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
*
*/
class PdoWriter implements WriterInterface
{
/**
* @var \PDO
*/
protected $pdo;

/**
* @var string
*/
protected $tableName;

/**
* @var \PDOStatement
*/
protected $statement;

/**
* Note if your table name is a reserved word for your target DB you should quote it in the appropriate way e.g.
* for MySQL enclose the name in `backticks`.
*
* @param \PDO $pdo
* @param string $tableName
*/
public function __construct(\PDO $pdo, $tableName)
{
$this->pdo = $pdo;
$this->tableName = $tableName;
}

/**
* {@inheritDoc}
*/
public function prepare()
{
}

/**
* {@inheritDoc}
*/
public function writeItem(array $item)
{
try {
//prepare the statment as soon as we know how many values there are
if (!$this->statement) {

$this->statement = $this->pdo->prepare(
'INSERT INTO '.$this->tableName.' VALUES ('.substr(str_repeat('?,', count($item)), 0, -1).')'
);

//for PDO objects that do not have exceptions enabled
if (!$this->statement) {
throw new WriterException('Failed to prepare write statement for item: '.implode(',', $item));
}
}

//do the insert
if (!$this->statement->execute(array_values($item))) {
throw new WriterException('Failed to write item: '.implode(',', $item));
}

} catch (\Exception $e) {
//convert exception so the abstracton doesn't leak
throw new WriterException('Write failed ('.$e->getMessage().').', null, $e);
}
}

/**
* {@inheritDoc}
*/
public function finish()
{
}
}
106 changes: 106 additions & 0 deletions tests/Ddeboer/DataImport/Tests/Writer/PdoWriterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

namespace Ddeboer\DataImport\Tests\Writer;

use Ddeboer\DataImport\Writer\PdoWriter;

class PdoWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \PDO
*/
private $pdo;

public function setUp()
{
$this->pdo = new \PDO('sqlite::memory:');
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); //important
$this->pdo->exec('DROP TABLE IF EXISTS `example`');
$this->pdo->exec('CREATE TABLE `example` (a TEXT, b TEXT)');
}

public function testValidWriteItem()
{
$writer = new PdoWriter($this->pdo, 'example');
$writer->prepare();
$writer->writeItem(array('foo', 'bar'));
$writer->finish();

$stmnt = $this->pdo->query('SELECT * FROM `example`');
$this->assertEquals(
array(array('a'=>'foo', 'b'=>'bar')),
$stmnt->fetchAll(\PDO::FETCH_ASSOC),
'database does not contain expected row'
);
}

public function testValidWriteMultiple()
{
$writer = new PdoWriter($this->pdo, 'example');
$writer->prepare();
$writer->writeItem(array('foo', 'bar'));
$writer->writeItem(array('cat', 'dog'));
$writer->writeItem(array('ac', 'dc'));
$writer->finish();

$stmnt = $this->pdo->query('SELECT * FROM `example`');
$this->assertEquals(
array(array('a'=>'foo', 'b'=>'bar'), array('a'=>'cat', 'b'=>'dog'), array('a'=>'ac', 'b'=>'dc')),
$stmnt->fetchAll(\PDO::FETCH_ASSOC),
'database does not contain all expected rows'
);
}

/**
* @expectedException \Ddeboer\DataImport\Exception\WriterException
*/
public function testWriteTooManyValues()
{
$writer = new PdoWriter($this->pdo, 'example');
$writer->prepare();
$writer->writeItem(array('foo', 'bar', 'baz')); //expects two
$writer->finish();
}

/**
* @expectedException \Ddeboer\DataImport\Exception\WriterException
*/
public function testWriteToNonexistentTable()
{
$writer = new PdoWriter($this->pdo, 'foobar');
$writer->prepare();
$writer->writeItem(array('foo', 'bar'));
$writer->finish();
}

/**
* Tests PDO instance with silent errors.
*
* @expectedException \Ddeboer\DataImport\Exception\WriterException
*/
public function testStatementCreateFailureWithNoException()
{
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);

$writer = new PdoWriter($this->pdo, 'foob`ar');
$writer->prepare();
$writer->writeItem(array('foo', 'bar'));
$writer->finish();
}

/**
* Tests PDO instance with silent errors. First inert prepares the statement, second creates an exception.
*
* @expectedException \Ddeboer\DataImport\Exception\WriterException
*/
public function testWriteFailureWithNoException()
{
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);

$writer = new PdoWriter($this->pdo, 'example');
$writer->prepare();
$writer->writeItem(array('foo', 'bar'));
$writer->writeItem(array('foo', 'bar', 'baz'));
$writer->finish();
}
}

0 comments on commit b96417d

Please sign in to comment.