Skip to content

Commit edd6178

Browse files
Support Cake\I18n\Date and DateTime for inserts (#2348)
Co-authored-by: Matthew Peveler <matt.peveler@gmail.com>
1 parent b7641e4 commit edd6178

File tree

8 files changed

+259
-27
lines changed

8 files changed

+259
-27
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"ext-json": "*",
4848
"ext-pdo": "*",
4949
"cakephp/cakephp-codesniffer": "^5.0",
50+
"cakephp/i18n": "^5.0",
5051
"phpunit/phpunit": "^9.5.19",
5152
"symfony/yaml": "^3.4|^4.0|^5.0|^6.0|^7.0"
5253
},

src/Phinx/Db/Adapter/PdoAdapter.php

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
use Cake\Database\Query\InsertQuery;
1616
use Cake\Database\Query\SelectQuery;
1717
use Cake\Database\Query\UpdateQuery;
18+
use Cake\I18n\Date;
19+
use Cake\I18n\DateTime;
1820
use InvalidArgumentException;
1921
use PDO;
2022
use PDOException;
@@ -319,6 +321,32 @@ public function fetchAll(string $sql): array
319321
return $this->query($sql)->fetchAll();
320322
}
321323

324+
/**
325+
* Get the parameters array for prepared insert statement
326+
*
327+
* @param array $row Row to be inserted into DB
328+
* @return array
329+
*/
330+
protected function getInsertParameters(array $row): array
331+
{
332+
$params = [];
333+
foreach ($row as $value) {
334+
if ($value instanceof Literal) {
335+
continue;
336+
} elseif ($value instanceof DateTime) {
337+
$params[] = $value->toDateTimeString();
338+
} elseif ($value instanceof Date) {
339+
$params[] = $value->toDateString();
340+
} elseif (is_bool($value)) {
341+
$params[] = $this->castToBool($value);
342+
} else {
343+
$params[] = $value;
344+
}
345+
}
346+
347+
return $params;
348+
}
349+
322350
/**
323351
* @inheritDoc
324352
*/
@@ -342,21 +370,14 @@ public function insert(Table $table, array $row): void
342370
$this->output->writeln($sql);
343371
} else {
344372
$sql .= '(';
345-
$vals = [];
346373
$values = [];
347374
foreach ($row as $value) {
348375
$values[] = $value instanceof Literal ? (string)$value : '?';
349-
if (!($value instanceof Literal)) {
350-
if (is_bool($value)) {
351-
$vals[] = $this->castToBool($value);
352-
} else {
353-
$vals[] = $value;
354-
}
355-
}
356376
}
377+
$params = $this->getInsertParameters($row);
357378
$sql .= implode(', ', $values) . ')';
358379
$stmt = $this->getConnection()->prepare($sql);
359-
$stmt->execute($vals);
380+
$stmt->execute($params);
360381
}
361382
}
362383

@@ -424,21 +445,13 @@ public function bulkinsert(Table $table, array $rows): void
424445
}
425446
$sql .= implode(',', $queries);
426447
$stmt = $this->getConnection()->prepare($sql);
427-
$vals = [];
448+
$params = [];
428449

429450
foreach ($rows as $row) {
430-
foreach ($row as $v) {
431-
if ($v instanceof Literal) {
432-
continue;
433-
} elseif (is_bool($v)) {
434-
$vals[] = $this->castToBool($v);
435-
} else {
436-
$vals[] = $v;
437-
}
438-
}
451+
$params = array_merge($params, $this->getInsertParameters($row));
439452
}
440453

441-
$stmt->execute($vals);
454+
$stmt->execute($params);
442455
}
443456
}
444457

tests/Phinx/Console/Command/SeedRunTest.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public function testExecute()
6363
$command = $application->find('seed:run');
6464

6565
// mock the manager class
66-
/** @var Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
66+
/** @var \Phinx\Migration\Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
6767
$managerStub = $this->getMockBuilder('\Phinx\Migration\Manager')
6868
->setConstructorArgs([$this->config, $this->input, $this->output])
6969
->getMock();
@@ -102,7 +102,7 @@ public function testExecuteWithDsn()
102102
]);
103103

104104
// mock the manager class
105-
/** @var Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
105+
/** @var \Phinx\Migration\Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
106106
$managerStub = $this->getMockBuilder('\Phinx\Migration\Manager')
107107
->setConstructorArgs([$config, $this->input, $this->output])
108108
->getMock();
@@ -127,7 +127,7 @@ public function testExecuteWithEnvironmentOption()
127127
$command = $application->find('seed:run');
128128

129129
// mock the manager class
130-
/** @var Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
130+
/** @var \Phinx\Migration\Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
131131
$managerStub = $this->getMockBuilder('\Phinx\Migration\Manager')
132132
->setConstructorArgs([$this->config, $this->input, $this->output])
133133
->getMock();
@@ -153,7 +153,7 @@ public function testExecuteWithInvalidEnvironmentOption()
153153
$command = $application->find('seed:run');
154154

155155
// mock the manager class
156-
/** @var Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
156+
/** @var \Phinx\Migration\Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
157157
$managerStub = $this->getMockBuilder('\Phinx\Migration\Manager')
158158
->setConstructorArgs([$this->config, $this->input, $this->output])
159159
->getMock();
@@ -180,7 +180,7 @@ public function testDatabaseNameSpecified()
180180
$command = $application->find('seed:run');
181181

182182
// mock the manager class
183-
/** @var Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
183+
/** @var \Phinx\Migration\Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
184184
$managerStub = $this->getMockBuilder('\Phinx\Migration\Manager')
185185
->setConstructorArgs([$this->config, $this->input, $this->output])
186186
->getMock();
@@ -205,7 +205,7 @@ public function testExecuteMultipleSeeders()
205205
$command = $application->find('seed:run');
206206

207207
// mock the manager class
208-
/** @var Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
208+
/** @var \Phinx\Migration\Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
209209
$managerStub = $this->getMockBuilder('\Phinx\Migration\Manager')
210210
->setConstructorArgs([$this->config, $this->input, $this->output])
211211
->getMock();
@@ -256,7 +256,7 @@ public function testSeedRunMemorySqlite()
256256
$command = $application->find('seed:run');
257257

258258
// mock the manager class
259-
/** @var Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
259+
/** @var \Phinx\Migration\Manager|\PHPUnit\Framework\MockObject\MockObject $managerStub */
260260
$managerStub = $this->getMockBuilder('\Phinx\Migration\Manager')
261261
->setConstructorArgs([$config, $this->input, $this->output])
262262
->getMock();

tests/Phinx/Db/Adapter/MysqlAdapterTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
namespace Test\Phinx\Db\Adapter;
55

66
use Cake\Database\Query;
7+
use Cake\I18n\Date;
8+
use Cake\I18n\DateTime;
79
use InvalidArgumentException;
810
use PDO;
911
use PDOException;
@@ -2215,6 +2217,30 @@ public function testBulkInsertLiteral()
22152217
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column2']);
22162218
}
22172219

2220+
public function testBulkInsertDates(): void
2221+
{
2222+
$data = [
2223+
[
2224+
'name' => 'foo',
2225+
'created' => new Date(),
2226+
],
2227+
[
2228+
'name' => 'bar',
2229+
'created' => new DateTime(),
2230+
],
2231+
];
2232+
$table = new Table('table1', [], $this->adapter);
2233+
$table->addColumn('name', 'string')
2234+
->addColumn('created', 'datetime')
2235+
->insert($data)
2236+
->save();
2237+
$rows = $this->adapter->fetchAll('SELECT * FROM table1');
2238+
$this->assertEquals('foo', $rows[0]['name']);
2239+
$this->assertEquals('bar', $rows[1]['name']);
2240+
$this->assertEquals($data[0]['created']->toDateTimeString(), $rows[0]['created']);
2241+
$this->assertEquals($data[1]['created']->toDateTimeString(), $rows[1]['created']);
2242+
}
2243+
22182244
public function testInsertData()
22192245
{
22202246
$data = [
@@ -2287,6 +2313,34 @@ public function testInsertLiteral()
22872313
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column3']);
22882314
}
22892315

2316+
public function testInsertDates(): void
2317+
{
2318+
$data = [
2319+
[
2320+
'name' => 'foo',
2321+
'created' => new Date(),
2322+
'column3' => 'foo',
2323+
],
2324+
[
2325+
'name' => 'bar',
2326+
'created' => new DateTime(),
2327+
],
2328+
];
2329+
$table = new Table('table1', [], $this->adapter);
2330+
$table->addColumn('name', 'string')
2331+
->addColumn('created', 'datetime')
2332+
->addColumn('column3', 'string', ['null' => true, 'default' => null])
2333+
->insert($data)
2334+
->save();
2335+
$rows = $this->adapter->fetchAll('SELECT * FROM table1');
2336+
$this->assertEquals('foo', $rows[0]['name']);
2337+
$this->assertEquals('bar', $rows[1]['name']);
2338+
$this->assertEquals($data[0]['created']->toDateTimeString(), $rows[0]['created']);
2339+
$this->assertEquals($data[1]['created']->toDateTimeString(), $rows[1]['created']);
2340+
$this->assertEquals('foo', $rows[0]['column3']);
2341+
$this->assertNull($rows[1]['column3']);
2342+
}
2343+
22902344
public function testDumpCreateTable()
22912345
{
22922346
$inputDefinition = new InputDefinition([new InputOption('dry-run')]);

tests/Phinx/Db/Adapter/PostgresAdapterTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
namespace Test\Phinx\Db\Adapter;
55

66
use Cake\Database\Query;
7+
use Cake\I18n\Date;
8+
use Cake\I18n\DateTime;
79
use InvalidArgumentException;
810
use PDO;
911
use Phinx\Db\Adapter\AbstractAdapter;
@@ -2447,6 +2449,30 @@ public function testBulkInsertLiteral()
24472449
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column2']);
24482450
}
24492451

2452+
public function testBulkInsertDates(): void
2453+
{
2454+
$data = [
2455+
[
2456+
'name' => 'foo',
2457+
'created' => new Date(),
2458+
],
2459+
[
2460+
'name' => 'bar',
2461+
'created' => new DateTime(),
2462+
],
2463+
];
2464+
$table = new Table('table1', [], $this->adapter);
2465+
$table->addColumn('name', 'string')
2466+
->addColumn('created', 'datetime')
2467+
->insert($data)
2468+
->save();
2469+
$rows = $this->adapter->fetchAll('SELECT * FROM table1');
2470+
$this->assertEquals('foo', $rows[0]['name']);
2471+
$this->assertEquals('bar', $rows[1]['name']);
2472+
$this->assertEquals($data[0]['created']->toDateTimeString(), $rows[0]['created']);
2473+
$this->assertEquals($data[1]['created']->toDateTimeString(), $rows[1]['created']);
2474+
}
2475+
24502476
public function testInsertData()
24512477
{
24522478
$table = new Table('table1', [], $this->adapter);
@@ -2532,6 +2558,34 @@ public function testInsertLiteral()
25322558
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column3']);
25332559
}
25342560

2561+
public function testInsertDates(): void
2562+
{
2563+
$data = [
2564+
[
2565+
'name' => 'foo',
2566+
'created' => new Date(),
2567+
'column3' => 'foo',
2568+
],
2569+
[
2570+
'name' => 'bar',
2571+
'created' => new DateTime(),
2572+
],
2573+
];
2574+
$table = new Table('table1', [], $this->adapter);
2575+
$table->addColumn('name', 'string')
2576+
->addColumn('created', 'datetime')
2577+
->addColumn('column3', 'string', ['null' => true, 'default' => null])
2578+
->insert($data)
2579+
->save();
2580+
$rows = $this->adapter->fetchAll('SELECT * FROM table1');
2581+
$this->assertEquals('foo', $rows[0]['name']);
2582+
$this->assertEquals('bar', $rows[1]['name']);
2583+
$this->assertEquals($data[0]['created']->toDateTimeString(), $rows[0]['created']);
2584+
$this->assertEquals($data[1]['created']->toDateTimeString(), $rows[1]['created']);
2585+
$this->assertEquals('foo', $rows[0]['column3']);
2586+
$this->assertNull($rows[1]['column3']);
2587+
}
2588+
25352589
public function testInsertDataWithSchema()
25362590
{
25372591
$this->adapter->createSchema('schema1');

tests/Phinx/Db/Adapter/SQLiteAdapterTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
use BadMethodCallException;
77
use Cake\Database\Query;
8+
use Cake\I18n\Date;
9+
use Cake\I18n\DateTime;
810
use Exception;
911
use InvalidArgumentException;
1012
use PDO;
@@ -1901,6 +1903,58 @@ public function testBulkInsertDataEnum()
19011903
$this->assertEquals('c', $rows[0]['column3']);
19021904
}
19031905

1906+
public function testBulkInsertDates(): void
1907+
{
1908+
$data = [
1909+
[
1910+
'name' => 'foo',
1911+
'created' => new Date(),
1912+
],
1913+
[
1914+
'name' => 'bar',
1915+
'created' => new DateTime(),
1916+
],
1917+
];
1918+
$table = new Table('table1', [], $this->adapter);
1919+
$table->addColumn('name', 'string')
1920+
->addColumn('created', 'datetime')
1921+
->insert($data)
1922+
->save();
1923+
$rows = $this->adapter->fetchAll('SELECT * FROM table1');
1924+
$this->assertEquals('foo', $rows[0]['name']);
1925+
$this->assertEquals('bar', $rows[1]['name']);
1926+
$this->assertEquals($data[0]['created']->toDateString(), $rows[0]['created']);
1927+
$this->assertEquals($data[1]['created']->toDateTimeString(), $rows[1]['created']);
1928+
}
1929+
1930+
public function testInsertDates(): void
1931+
{
1932+
$data = [
1933+
[
1934+
'name' => 'foo',
1935+
'created' => new Date(),
1936+
'column3' => 'foo',
1937+
],
1938+
[
1939+
'name' => 'bar',
1940+
'created' => new DateTime(),
1941+
],
1942+
];
1943+
$table = new Table('table1', [], $this->adapter);
1944+
$table->addColumn('name', 'string')
1945+
->addColumn('created', 'datetime')
1946+
->addColumn('column3', 'string', ['null' => true, 'default' => null])
1947+
->insert($data)
1948+
->save();
1949+
$rows = $this->adapter->fetchAll('SELECT * FROM table1');
1950+
$this->assertEquals('foo', $rows[0]['name']);
1951+
$this->assertEquals('bar', $rows[1]['name']);
1952+
$this->assertEquals($data[0]['created']->toDateString(), $rows[0]['created']);
1953+
$this->assertEquals($data[1]['created']->toDateTimeString(), $rows[1]['created']);
1954+
$this->assertEquals('foo', $rows[0]['column3']);
1955+
$this->assertNull($rows[1]['column3']);
1956+
}
1957+
19041958
public function testNullWithoutDefaultValue()
19051959
{
19061960
$this->markTestSkipped('Skipping for now. See Github Issue #265.');

0 commit comments

Comments
 (0)