Skip to content

Commit

Permalink
Merge branch 'feature/replace'
Browse files Browse the repository at this point in the history
  • Loading branch information
cambell-prince committed Mar 16, 2019
2 parents 62ad308 + 4371542 commit f0b887a
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 17 deletions.
67 changes: 50 additions & 17 deletions src/DataMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class DataMapper
/** @var string The property in the model that is used as the primary key */
public $modelPrimaryKey = 'id';

/** @var bool If true REPLACE is used rather than INSERT and UPDATE */
public $useReplace = false;

/** @var string Name of the table */
public $table;

Expand Down Expand Up @@ -104,30 +107,60 @@ public static function autoMap($c)
public function write(&$c)
{
$key = $this->modelPrimaryKey;
$set = '';
foreach ($this->map as $property => $field) {
if ($property == $key || $property[0] == '_') {
continue;
if ($this->useReplace) {
if (!$c->$key) {
throw new \Exception("Key '$key' must be set when using replace mode");
}
if ($set) {
$set .= ', ';
$fields = '';
$values = '';
foreach ($this->map as $property => $field) {
if ($property[0] == '_') {
continue;
}
if ($fields) {
$fields .= ', ';
}
if ($values) {
$values .= ', ';
}
$fields .= $field;
$value = $c->$property;
$values .= "'$value'";
}
$value = $c->$property;
$set .= "$field='$value'";
}
if ($c->$key === null) {
$sql = 'INSERT INTO `' . $this->table . '` SET ' . $set;
$this->dynamicWrapper(function () use ($sql, $c, $key) {
$result = $this->pdo->query($sql);
$c->$key = $this->pdo->lastInsertId();
}, $c);
} else {
$keyField = $this->map[$key];
$id = $c->$key;
$sql = 'UPDATE `' . $this->table . '` SET ' . $set . ' WHERE ' . $keyField . "='" . $id . "'";
// CP Maybe REPLACE isn't the best to use? It requires a unique key in the db
// An alternative would be to detect based on SELECT query WHERE key and if found ...
$sql = 'REPLACE INTO`' . $this->table . '` (' . $fields . ') VALUES (' . $values . ')';
$this->dynamicWrapper(function () use ($sql) {
$this->pdo->query($sql);
}, $c);
} else {
$set = '';
foreach ($this->map as $property => $field) {
if ($property == $key || $property[0] == '_') {
continue;
}
if ($set) {
$set .= ', ';
}
$value = $c->$property;
$set .= "$field='$value'";
}
if ($c->$key === null) {
$sql = 'INSERT INTO `' . $this->table . '` SET ' . $set;
$this->dynamicWrapper(function () use ($sql, $c, $key) {
$result = $this->pdo->query($sql);
$c->$key = $this->pdo->lastInsertId();
}, $c);
} else {
$keyField = $this->map[$key];
$id = $c->$key;
$sql = 'UPDATE `' . $this->table . '` SET ' . $set . ' WHERE ' . $keyField . "='" . $id . "'";
$this->dynamicWrapper(function () use ($sql) {
$this->pdo->query($sql);
}, $c);
}
}
return $c->$key;
}
Expand Down
77 changes: 77 additions & 0 deletions test/anorm/DataMapper_Replace_Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

require_once(__DIR__ . '/../../vendor/autoload.php');

require_once(__DIR__ . '/ReplaceTableModel.php');

use PHPUnit\Framework\TestCase;

class DataMapperReplaceTest extends TestCase
{
/** @var \PDO */
private $pdo;

public function __construct()
{
parent::__construct();
$this->pdo = new \PDO('mysql:host=localhost;dbname=anorm_test', 'travis', '');
}

public static function setUpBeforeClass()
{
$pdo = new \PDO('mysql:host=localhost;dbname=anorm_test', 'travis', '');
$pdo->query('DROP TABLE IF EXISTS `replace_table`');
$sql = file_get_contents(__DIR__ . '/TestReplaceSchema.sql');
$pdo->query($sql);
}

public function testReplace_OK()
{
$model0 = new ReplaceTableModel($this->pdo);
$this->assertEquals($this->pdo, $model0->_mapper->pdo);
// Count current rows
$n0 = $model0->countRows();
$this->assertEquals(0, $n0);

// Create
$model0->replaceId = 'bob_id';
$model0->name = 'bob';
$model0->write();

// Count current rows (n+1)
$n1 = $model0->countRows();
$this->assertEquals($n0 + 1, $n1);

// Read (data present)
$model1 = new ReplaceTableModel($this->pdo);
$model1->read($model0->replaceId);
$this->assertEquals($model0->name, $model1->name);

// Update
$model1->name = 'fred';
$model1->write();

// Read (data changed)
$model2 = new ReplaceTableModel($this->pdo);
$model2->read($model1->replaceId);
$this->assertEquals($model1->name, $model2->name);

// Delete
$model0->_mapper->delete($model0->replaceId);

// Count current rows (n)
$n2 = $model0->countRows();
$this->assertEquals($n0, $n2);

}

/**
* @expectedException \Exception
* @expectedExceptionMessage Key 'replaceId' must be set when using replace mode
*/
public function testNoPrimaryKey_Throws()
{
$model = new ReplaceTableModel($this->pdo);
$model->write();
}
}
23 changes: 23 additions & 0 deletions test/anorm/ReplaceTableModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

use Anorm\DataMapper;
use Anorm\Model;

class ReplaceTableModel extends Model {
public function __construct(\PDO $pdo)
{
parent::__construct($pdo, DataMapper::createByClass($pdo, $this));
$this->_mapper->modelPrimaryKey = 'replaceId';
$this->_mapper->useReplace = true;
}

public function countRows()
{
$result = $this->_mapper->query('SELECT * FROM `replace_table`');
return $result->rowCount();
}

public $replaceId;
public $name;
}

8 changes: 8 additions & 0 deletions test/anorm/TestReplaceSchema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# USE `anorm_test`;
# DROP TABLE `replace_table` IF EXISTS;
CREATE TABLE `replace_table` (
`replace_id` varchar(32) NOT NULL,
`name` varchar(128) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `replace_table`
ADD UNIQUE KEY `replace_id` (`replace_id`);

0 comments on commit f0b887a

Please sign in to comment.