Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit 5294450

Browse files
committed
Merge branch 'feature/336' into develop
Close #336
2 parents 8c3493a + 1f68156 commit 5294450

File tree

3 files changed

+384
-1
lines changed

3 files changed

+384
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ All notable changes to this project will be documented in this file, in reverse
66

77
### Added
88

9-
- Nothing.
9+
- [#336](https://github.com/zendframework/zend-db/pull/336) adds `InsertIgnore` class for "INSERT IGNORE" usage (usable in `MySQL` platform).
1010

1111
### Changed
1212

src/Sql/InsertIgnore.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
/**
3+
* @see https://github.com/zendframework/zend-db for the canonical source repository
4+
* @copyright Copyright (c) 2019 Zend Technologies USA Inc. (https://www.zend.com)
5+
* @license https://github.com/zendframework/zend-db/blob/master/LICENSE.md New BSD License
6+
*/
7+
8+
namespace Zend\Db\Sql;
9+
10+
class InsertIgnore extends Insert
11+
{
12+
/**
13+
* @var array Specification array
14+
*/
15+
protected $specifications = [
16+
self::SPECIFICATION_INSERT => 'INSERT IGNORE INTO %1$s (%2$s) VALUES (%3$s)',
17+
self::SPECIFICATION_SELECT => 'INSERT IGNORE INTO %1$s %2$s %3$s',
18+
];
19+
}

test/unit/Sql/InsertIgnoreTest.php

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
<?php
2+
/**
3+
* @see https://github.com/zendframework/zend-db for the canonical source repository
4+
* @copyright Copyright (c) 2019 Zend Technologies USA Inc. (https://www.zend.com)
5+
* @license https://github.com/zendframework/zend-db/blob/master/LICENSE.md New BSD License
6+
*/
7+
8+
namespace ZendTest\Db\Sql;
9+
10+
use PHPUnit\Framework\TestCase;
11+
use Zend\Db\Sql\Expression;
12+
use Zend\Db\Sql\InsertIgnore;
13+
use Zend\Db\Sql\Select;
14+
use Zend\Db\Sql\TableIdentifier;
15+
use ZendTest\Db\TestAsset\Replace;
16+
use ZendTest\Db\TestAsset\TrustingSql92Platform;
17+
18+
class InsertIgnoreTest extends TestCase
19+
{
20+
/**
21+
* @var InsertIgnore
22+
*/
23+
protected $insert;
24+
25+
/**
26+
* Sets up the fixture, for example, opens a network connection.
27+
* This method is called before a test is executed.
28+
*/
29+
protected function setUp()
30+
{
31+
$this->insert = new InsertIgnore;
32+
}
33+
34+
public function testInto()
35+
{
36+
$this->insert->into('table');
37+
self::assertEquals('table', $this->insert->getRawState('table'));
38+
39+
$tableIdentifier = new TableIdentifier('table', 'schema');
40+
$this->insert->into($tableIdentifier);
41+
self::assertEquals($tableIdentifier, $this->insert->getRawState('table'));
42+
}
43+
44+
public function testColumns()
45+
{
46+
$columns = ['foo', 'bar'];
47+
$this->insert->columns($columns);
48+
self::assertEquals($columns, $this->insert->getRawState('columns'));
49+
}
50+
51+
public function testValues()
52+
{
53+
$this->insert->values(['foo' => 'bar']);
54+
self::assertEquals(['foo'], $this->insert->getRawState('columns'));
55+
self::assertEquals(['bar'], $this->insert->getRawState('values'));
56+
57+
// test will merge cols and values of previously set stuff
58+
$this->insert->values(['foo' => 'bax'], InsertIgnore::VALUES_MERGE);
59+
$this->insert->values(['boom' => 'bam'], InsertIgnore::VALUES_MERGE);
60+
self::assertEquals(['foo', 'boom'], $this->insert->getRawState('columns'));
61+
self::assertEquals(['bax', 'bam'], $this->insert->getRawState('values'));
62+
63+
$this->insert->values(['foo' => 'bax']);
64+
self::assertEquals(['foo'], $this->insert->getRawState('columns'));
65+
self::assertEquals(['bax'], $this->insert->getRawState('values'));
66+
}
67+
68+
public function testValuesThrowsExceptionWhenNotArrayOrSelect()
69+
{
70+
$this->expectException('Zend\Db\Sql\Exception\InvalidArgumentException');
71+
$this->expectExceptionMessage('values() expects an array of values or Zend\Db\Sql\Select instance');
72+
$this->insert->values(5);
73+
}
74+
75+
public function testValuesThrowsExceptionWhenSelectMergeOverArray()
76+
{
77+
$this->insert->values(['foo' => 'bar']);
78+
79+
$this->expectException('Zend\Db\Sql\Exception\InvalidArgumentException');
80+
$this->expectExceptionMessage('A Zend\Db\Sql\Select instance cannot be provided with the merge flag');
81+
$this->insert->values(new Select, InsertIgnore::VALUES_MERGE);
82+
}
83+
84+
public function testValuesThrowsExceptionWhenArrayMergeOverSelect()
85+
{
86+
$this->insert->values(new Select);
87+
88+
$this->expectException('Zend\Db\Sql\Exception\InvalidArgumentException');
89+
$this->expectExceptionMessage(
90+
'An array of values cannot be provided with the merge flag when a Zend\Db\Sql\Select instance already '
91+
. 'exists as the value source'
92+
);
93+
$this->insert->values(['foo' => 'bar'], InsertIgnore::VALUES_MERGE);
94+
}
95+
96+
/**
97+
* @group ZF2-4926
98+
*/
99+
public function testEmptyArrayValues()
100+
{
101+
$this->insert->values([]);
102+
self::assertEquals([], $this->readAttribute($this->insert, 'columns'));
103+
}
104+
105+
public function testPrepareStatement()
106+
{
107+
$mockDriver = $this->getMockBuilder('Zend\Db\Adapter\Driver\DriverInterface')->getMock();
108+
$mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional'));
109+
$mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?'));
110+
$mockAdapter = $this->getMockBuilder('Zend\Db\Adapter\Adapter')
111+
->setMethods()
112+
->setConstructorArgs([$mockDriver])
113+
->getMock();
114+
115+
$mockStatement = $this->getMockBuilder('Zend\Db\Adapter\Driver\StatementInterface')->getMock();
116+
$pContainer = new \Zend\Db\Adapter\ParameterContainer([]);
117+
$mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer));
118+
$mockStatement->expects($this->at(1))
119+
->method('setSql')
120+
->with($this->equalTo('INSERT IGNORE INTO "foo" ("bar", "boo") VALUES (?, NOW())'));
121+
122+
$this->insert->into('foo')
123+
->values(['bar' => 'baz', 'boo' => new Expression('NOW()')]);
124+
125+
$this->insert->prepareStatement($mockAdapter, $mockStatement);
126+
127+
// with TableIdentifier
128+
$this->insert = new InsertIgnore;
129+
$mockDriver = $this->getMockBuilder('Zend\Db\Adapter\Driver\DriverInterface')->getMock();
130+
$mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional'));
131+
$mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?'));
132+
$mockAdapter = $this->getMockBuilder('Zend\Db\Adapter\Adapter')
133+
->setMethods()
134+
->setConstructorArgs([$mockDriver])
135+
->getMock();
136+
137+
$mockStatement = $this->getMockBuilder('Zend\Db\Adapter\Driver\StatementInterface')->getMock();
138+
$pContainer = new \Zend\Db\Adapter\ParameterContainer([]);
139+
$mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer));
140+
$mockStatement->expects($this->at(1))
141+
->method('setSql')
142+
->with($this->equalTo('INSERT IGNORE INTO "sch"."foo" ("bar", "boo") VALUES (?, NOW())'));
143+
144+
$this->insert->into(new TableIdentifier('foo', 'sch'))
145+
->values(['bar' => 'baz', 'boo' => new Expression('NOW()')]);
146+
147+
$this->insert->prepareStatement($mockAdapter, $mockStatement);
148+
}
149+
150+
public function testPrepareStatementWithSelect()
151+
{
152+
$mockDriver = $this->getMockBuilder('Zend\Db\Adapter\Driver\DriverInterface')->getMock();
153+
$mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional'));
154+
$mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?'));
155+
$mockAdapter = $this->getMockBuilder('Zend\Db\Adapter\Adapter')
156+
->setMethods()
157+
->setConstructorArgs([$mockDriver])
158+
->getMock();
159+
160+
$mockStatement = new \Zend\Db\Adapter\StatementContainer();
161+
162+
$select = new Select('bar');
163+
$this->insert
164+
->into('foo')
165+
->columns(['col1'])
166+
->select($select->where(['x' => 5]))
167+
->prepareStatement($mockAdapter, $mockStatement);
168+
169+
self::assertEquals(
170+
'INSERT IGNORE INTO "foo" ("col1") SELECT "bar".* FROM "bar" WHERE "x" = ?',
171+
$mockStatement->getSql()
172+
);
173+
$parameters = $mockStatement->getParameterContainer()->getNamedArray();
174+
self::assertSame(['subselect1where1' => 5], $parameters);
175+
}
176+
177+
public function testGetSqlString()
178+
{
179+
$this->insert->into('foo')
180+
->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]);
181+
182+
self::assertEquals(
183+
'INSERT IGNORE INTO "foo" ("bar", "boo", "bam") VALUES (\'baz\', NOW(), NULL)',
184+
$this->insert->getSqlString(new TrustingSql92Platform())
185+
);
186+
187+
// with TableIdentifier
188+
$this->insert = new InsertIgnore;
189+
$this->insert->into(new TableIdentifier('foo', 'sch'))
190+
->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]);
191+
192+
self::assertEquals(
193+
'INSERT IGNORE INTO "sch"."foo" ("bar", "boo", "bam") VALUES (\'baz\', NOW(), NULL)',
194+
$this->insert->getSqlString(new TrustingSql92Platform())
195+
);
196+
197+
// with Select
198+
$this->insert = new InsertIgnore;
199+
$select = new Select();
200+
$this->insert->into('foo')->select($select->from('bar'));
201+
202+
self::assertEquals(
203+
'INSERT IGNORE INTO "foo" SELECT "bar".* FROM "bar"',
204+
$this->insert->getSqlString(new TrustingSql92Platform())
205+
);
206+
207+
// with Select and columns
208+
$this->insert->columns(['col1', 'col2']);
209+
self::assertEquals(
210+
'INSERT IGNORE INTO "foo" ("col1", "col2") SELECT "bar".* FROM "bar"',
211+
$this->insert->getSqlString(new TrustingSql92Platform())
212+
);
213+
}
214+
215+
public function testGetSqlStringUsingColumnsAndValuesMethods()
216+
{
217+
// With columns() and values()
218+
$this->insert
219+
->into('foo')
220+
->columns(['col1', 'col2', 'col3'])
221+
->values(['val1', 'val2', 'val3']);
222+
self::assertEquals(
223+
'INSERT IGNORE INTO "foo" ("col1", "col2", "col3") VALUES (\'val1\', \'val2\', \'val3\')',
224+
$this->insert->getSqlString(new TrustingSql92Platform())
225+
);
226+
}
227+
228+
// @codingStandardsIgnoreStart
229+
public function test__set()
230+
{
231+
// @codingStandardsIgnoreEnd
232+
$this->insert->foo = 'bar';
233+
self::assertEquals(['foo'], $this->insert->getRawState('columns'));
234+
self::assertEquals(['bar'], $this->insert->getRawState('values'));
235+
}
236+
237+
// @codingStandardsIgnoreStart
238+
public function test__unset()
239+
{
240+
// @codingStandardsIgnoreEnd
241+
$this->insert->foo = 'bar';
242+
self::assertEquals(['foo'], $this->insert->getRawState('columns'));
243+
self::assertEquals(['bar'], $this->insert->getRawState('values'));
244+
unset($this->insert->foo);
245+
self::assertEquals([], $this->insert->getRawState('columns'));
246+
self::assertEquals([], $this->insert->getRawState('values'));
247+
248+
$this->insert->foo = null;
249+
self::assertEquals(['foo'], $this->insert->getRawState('columns'));
250+
self::assertEquals([null], $this->insert->getRawState('values'));
251+
252+
unset($this->insert->foo);
253+
self::assertEquals([], $this->insert->getRawState('columns'));
254+
self::assertEquals([], $this->insert->getRawState('values'));
255+
}
256+
257+
// @codingStandardsIgnoreStart
258+
public function test__isset()
259+
{
260+
// @codingStandardsIgnoreEnd
261+
$this->insert->foo = 'bar';
262+
self::assertTrue(isset($this->insert->foo));
263+
264+
$this->insert->foo = null;
265+
self::assertTrue(isset($this->insert->foo));
266+
}
267+
268+
// @codingStandardsIgnoreStart
269+
public function test__get()
270+
{
271+
// @codingStandardsIgnoreEnd
272+
$this->insert->foo = 'bar';
273+
self::assertEquals('bar', $this->insert->foo);
274+
275+
$this->insert->foo = null;
276+
self::assertNull($this->insert->foo);
277+
}
278+
279+
/**
280+
* @group ZF2-536
281+
*/
282+
public function testValuesMerge()
283+
{
284+
$this->insert->into('foo')
285+
->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]);
286+
$this->insert->into('foo')
287+
->values(['qux' => 100], InsertIgnore::VALUES_MERGE);
288+
289+
self::assertEquals(
290+
'INSERT IGNORE INTO "foo" ("bar", "boo", "bam", "qux") VALUES (\'baz\', NOW(), NULL, \'100\')',
291+
$this->insert->getSqlString(new TrustingSql92Platform())
292+
);
293+
}
294+
295+
public function testSpecificationconstantsCouldBeOverridedByExtensionInPrepareStatement()
296+
{
297+
$replace = new Replace();
298+
299+
$mockDriver = $this->getMockBuilder('Zend\Db\Adapter\Driver\DriverInterface')->getMock();
300+
$mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional'));
301+
$mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?'));
302+
$mockAdapter = $this->getMockBuilder('Zend\Db\Adapter\Adapter')
303+
->setMethods()
304+
->setConstructorArgs([$mockDriver])
305+
->getMock();
306+
307+
$mockStatement = $this->getMockBuilder('Zend\Db\Adapter\Driver\StatementInterface')->getMock();
308+
$pContainer = new \Zend\Db\Adapter\ParameterContainer([]);
309+
$mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer));
310+
$mockStatement->expects($this->at(1))
311+
->method('setSql')
312+
->with($this->equalTo('REPLACE INTO "foo" ("bar", "boo") VALUES (?, NOW())'));
313+
314+
$replace->into('foo')
315+
->values(['bar' => 'baz', 'boo' => new Expression('NOW()')]);
316+
317+
$replace->prepareStatement($mockAdapter, $mockStatement);
318+
319+
// with TableIdentifier
320+
$replace = new Replace();
321+
322+
$mockDriver = $this->getMockBuilder('Zend\Db\Adapter\Driver\DriverInterface')->getMock();
323+
$mockDriver->expects($this->any())->method('getPrepareType')->will($this->returnValue('positional'));
324+
$mockDriver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?'));
325+
$mockAdapter = $this->getMockBuilder('Zend\Db\Adapter\Adapter')
326+
->setMethods()
327+
->setConstructorArgs([$mockDriver])
328+
->getMock();
329+
330+
$mockStatement = $this->getMockBuilder('Zend\Db\Adapter\Driver\StatementInterface')->getMock();
331+
$pContainer = new \Zend\Db\Adapter\ParameterContainer([]);
332+
$mockStatement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($pContainer));
333+
$mockStatement->expects($this->at(1))
334+
->method('setSql')
335+
->with($this->equalTo('REPLACE INTO "sch"."foo" ("bar", "boo") VALUES (?, NOW())'));
336+
337+
$replace->into(new TableIdentifier('foo', 'sch'))
338+
->values(['bar' => 'baz', 'boo' => new Expression('NOW()')]);
339+
340+
$replace->prepareStatement($mockAdapter, $mockStatement);
341+
}
342+
343+
public function testSpecificationconstantsCouldBeOverridedByExtensionInGetSqlString()
344+
{
345+
$replace = new Replace();
346+
$replace->into('foo')
347+
->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]);
348+
349+
self::assertEquals(
350+
'REPLACE INTO "foo" ("bar", "boo", "bam") VALUES (\'baz\', NOW(), NULL)',
351+
$replace->getSqlString(new TrustingSql92Platform())
352+
);
353+
354+
// with TableIdentifier
355+
$replace = new Replace();
356+
$replace->into(new TableIdentifier('foo', 'sch'))
357+
->values(['bar' => 'baz', 'boo' => new Expression('NOW()'), 'bam' => null]);
358+
359+
self::assertEquals(
360+
'REPLACE INTO "sch"."foo" ("bar", "boo", "bam") VALUES (\'baz\', NOW(), NULL)',
361+
$replace->getSqlString(new TrustingSql92Platform())
362+
);
363+
}
364+
}

0 commit comments

Comments
 (0)