Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
paxuclus authored and saschanowak committed Jan 28, 2021
0 parents commit 2875cd6
Show file tree
Hide file tree
Showing 10 changed files with 480 additions and 0 deletions.
21 changes: 21 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "netlogix/doctrine-upsert",
"description": "Doctrine upsert helper",
"license": "MIT",
"type": "library",
"require": {
"doctrine/dbal": "^2.9"
},
"require-dev": {
"phpunit/phpunit": "^6.0",
"ext-pdo_sqlite": "*"
},
"autoload": {
"psr-4": {
"Netlogix\\Doctrine\\Upsert\\": "src/"
}
},
"replace": {
"netlogix/doctrine-upsert": "self.version"
}
}
10 changes: 10 additions & 0 deletions src/Exception/EmptyUpsert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);

namespace Netlogix\Doctrine\Upsert\Exception;

use Exception;

class EmptyUpsert extends Exception
{
}
10 changes: 10 additions & 0 deletions src/Exception/FieldAlreadyInUse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);

namespace Netlogix\Doctrine\Upsert\Exception;

use Exception;

class FieldAlreadyInUse extends Exception
{
}
10 changes: 10 additions & 0 deletions src/Exception/FieldRegisteredAsIdentifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);

namespace Netlogix\Doctrine\Upsert\Exception;

use Exception;

class FieldRegisteredAsIdentifier extends Exception
{
}
10 changes: 10 additions & 0 deletions src/Exception/IdentifierAlreadyInUse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);

namespace Netlogix\Doctrine\Upsert\Exception;

use Exception;

class IdentifierAlreadyInUse extends Exception
{
}
10 changes: 10 additions & 0 deletions src/Exception/IdentifierRegisteredAsField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);

namespace Netlogix\Doctrine\Upsert\Exception;

use Exception;

class IdentifierRegisteredAsField extends Exception
{
}
10 changes: 10 additions & 0 deletions src/Exception/NoTableGiven.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);

namespace Netlogix\Doctrine\Upsert\Exception;

use Exception;

class NoTableGiven extends Exception
{
}
10 changes: 10 additions & 0 deletions src/Exception/UnsupportedDatabasePlatform.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);

namespace Netlogix\Doctrine\Upsert\Exception;

use Exception;

class UnsupportedDatabasePlatform extends Exception
{
}
137 changes: 137 additions & 0 deletions src/Upsert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php
declare(strict_types=1);

namespace Netlogix\Doctrine\Upsert;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\ParameterType;
use Netlogix\Doctrine\Upsert\Exception;

class Upsert
{

/**
* @var Connection
*/
private $connection;

/**
* @var string
*/
private $table;

/**
* @var array
*/
private $identifiers = [];

/**
* @var array
*/
private $fields = [];

private function __construct(Connection $connection)
{
$this->connection = $connection;
}

public function forTable(string $table): self
{
$this->table = $table;

return $this;
}

public function withIdentifier(string $column, $value, int $parameterType = ParameterType::STRING): self
{
if (array_key_exists($column, $this->identifiers)) {
throw new Exception\IdentifierAlreadyInUse(sprintf('The identifier "%s" has already been set!', $column), 1603196381);
}
if (array_key_exists($column, $this->fields)) {
throw new Exception\IdentifierRegisteredAsField(sprintf('The identifier "%s" has already been set as field!', $column), 1603197666);
}

$this->identifiers[$column] = [
'value' => $value,
'type' => $parameterType,
];

return $this;
}

public function withField(string $column, $value, int $parameterType = ParameterType::STRING): self
{
if (array_key_exists($column, $this->fields)) {
throw new Exception\FieldAlreadyInUse(sprintf('The field "%s" has already been set!', $column), 1603196457);
}
if (array_key_exists($column, $this->identifiers)) {
throw new Exception\FieldRegisteredAsIdentifier(sprintf('The field "%s" has already been set as identifier!', $column), 1603197691);
}

$this->fields[$column] = [
'value' => $value,
'type' => $parameterType,
];

return $this;
}

public function execute(): void
{
if (!$this->table) {
throw new Exception\NoTableGiven('No table name has been set!', 1603199471);
}
if (count($this->identifiers) === 0 || count($this->fields) === 0) {
throw new Exception\EmptyUpsert('No columns have been specified for upsert!', 1603199389);
}

$allFields = array_merge($this->fields, $this->identifiers);

$columns = implode(', ', array_keys($allFields));
$values = implode(', ', array_map(function(string $column) {
return ':' . $column;
}, array_keys($allFields)));

$updates = implode(', ', array_map(function(string $column) {
return $column . ' = :' . $column;
}, array_keys($this->fields)));

$sql = $this->buildQuery($columns, $values, $updates);

$this->connection->executeQuery(
$sql,
array_combine(array_keys($allFields), array_column($allFields, 'value')),
array_combine(array_keys($allFields), array_column($allFields, 'type'))
);
}

protected function buildQuery(string $columns, string $values, string $updates): string
{
switch($this->connection->getDatabasePlatform()->getName()) {
case 'mysql':
return <<<MYSQL
INSERT INTO {$this->table} ({$columns})
VALUES ({$values})
ON DUPLICATE KEY UPDATE {$updates}
MYSQL;
case 'sqlite':
$conflictColumns = implode(', ', array_keys($this->identifiers));
return <<<SQLITE
INSERT INTO {$this->table} ({$columns})
VALUES ({$values})
ON CONFLICT({$conflictColumns}) DO UPDATE SET {$updates}
SQLITE;
default:
throw new Exception\UnsupportedDatabasePlatform(
sprintf('The database platform %s is not supported!', $this->connection->getDatabasePlatform()->getName()),
1603199935
);
}
}

public static function fromConnection(Connection $connection): self
{
return new static($connection);
}

}
Loading

0 comments on commit 2875cd6

Please sign in to comment.