Skip to content

Commit c57a16b

Browse files
authored
Merge pull request #14825 from marius-wieschollek/bugfix/11236
Set parameter type in QBMapper
2 parents e4d4e4d + 5aeb8ea commit c57a16b

2 files changed

Lines changed: 276 additions & 3 deletions

File tree

lib/public/AppFramework/Db/QBMapper.php

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ public function insert(Entity $entity): Entity {
114114
$getter = 'get' . ucfirst($property);
115115
$value = $entity->$getter();
116116

117-
$qb->setValue($column, $qb->createNamedParameter($value));
117+
$type = $this->getParameterTypeForProperty($entity, $property);
118+
$qb->setValue($column, $qb->createNamedParameter($value, $type));
118119
}
119120

120121
$qb->execute();
@@ -181,17 +182,48 @@ public function update(Entity $entity): Entity {
181182
$getter = 'get' . ucfirst($property);
182183
$value = $entity->$getter();
183184

184-
$qb->set($column, $qb->createNamedParameter($value));
185+
$type = $this->getParameterTypeForProperty($entity, $property);
186+
$qb->set($column, $qb->createNamedParameter($value, $type));
185187
}
186188

187189
$qb->where(
188-
$qb->expr()->eq('id', $qb->createNamedParameter($id))
190+
$qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))
189191
);
190192
$qb->execute();
191193

192194
return $entity;
193195
}
194196

197+
/**
198+
* Returns the type parameter for the QueryBuilder for a specific property
199+
* of the $entity
200+
*
201+
* @param Entity $entity The entity to get the types from
202+
* @param string $property The property of $entity to get the type for
203+
* @return int
204+
* @since 16.0.0
205+
*/
206+
protected function getParameterTypeForProperty(Entity $entity, string $property): int {
207+
$types = $entity->getFieldTypes();
208+
209+
if(!isset($types[ $property ])) {
210+
return IQueryBuilder::PARAM_STR;
211+
}
212+
213+
switch($types[ $property ]) {
214+
case 'int':
215+
case 'integer':
216+
return IQueryBuilder::PARAM_INT;
217+
case 'string':
218+
return IQueryBuilder::PARAM_STR;
219+
case 'bool':
220+
case 'boolean':
221+
return IQueryBuilder::PARAM_BOOL;
222+
}
223+
224+
return IQueryBuilder::PARAM_STR;
225+
}
226+
195227
/**
196228
* Returns an db result and throws exceptions when there are more or less
197229
* results
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
<?php
2+
/**
3+
* @copyright 2019, Marius David Wieschollek <git.public@mdns.eu>
4+
*
5+
* @author Marius David Wieschollek <git.public@mdns.eu>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
namespace Test\AppFramework\Db;
25+
26+
use OCP\AppFramework\Db\Entity;
27+
use OCP\AppFramework\Db\QBMapper;
28+
use OCP\DB\QueryBuilder\IExpressionBuilder;
29+
use OCP\DB\QueryBuilder\IQueryBuilder;
30+
use OCP\IDBConnection;
31+
32+
/**
33+
* @method bool getBoolProp()
34+
* @method void setBoolProp(bool $boolProp)
35+
* @method integer getIntProp()
36+
* @method void setIntProp(integer $intProp)
37+
* @method string getStringProp()
38+
* @method void setStringProp(string $stringProp)
39+
* @method bool getBooleanProp()
40+
* @method void setBooleanProp(bool $booleanProp)
41+
* @method integer getIntegerProp()
42+
* @method void setIntegerProp(integer $integerProp)
43+
*/
44+
class QBTestEntity extends Entity {
45+
46+
protected $intProp;
47+
protected $boolProp;
48+
protected $stringProp;
49+
protected $integerProp;
50+
protected $booleanProp;
51+
52+
public function __construct() {
53+
$this->addType('intProp', 'int');
54+
$this->addType('boolProp', 'bool');
55+
$this->addType('stringProp', 'string');
56+
$this->addType('integerProp', 'integer');
57+
$this->addType('booleanProp', 'boolean');
58+
}
59+
}
60+
61+
;
62+
63+
/**
64+
* Class QBTestMapper
65+
*
66+
* @package Test\AppFramework\Db
67+
*/
68+
class QBTestMapper extends QBMapper {
69+
public function __construct(IDBConnection $db) {
70+
parent::__construct($db, 'table');
71+
}
72+
73+
public function getParameterTypeForPropertyForTest(Entity $entity, string $property): int {
74+
return parent::getParameterTypeForProperty($entity, $property);
75+
}
76+
}
77+
78+
/**
79+
* Class QBMapperTest
80+
*
81+
* @package Test\AppFramework\Db
82+
*/
83+
class QBMapperTest extends \Test\TestCase {
84+
85+
/**
86+
* @var \PHPUnit\Framework\MockObject\MockObject|IDBConnection
87+
*/
88+
protected $db;
89+
90+
/**
91+
* @var \PHPUnit\Framework\MockObject\MockObject|IQueryBuilder
92+
*/
93+
protected $qb;
94+
95+
/**
96+
* @var \PHPUnit\Framework\MockObject\MockObject|IExpressionBuilder
97+
*/
98+
protected $expr;
99+
100+
/**
101+
* @var \Test\AppFramework\Db\QBTestMapper
102+
*/
103+
protected $mapper;
104+
105+
/**
106+
* @throws \ReflectionException
107+
*/
108+
protected function setUp() {
109+
110+
$this->db = $this->getMockBuilder(IDBConnection::class)
111+
->disableOriginalConstructor()
112+
->getMock();
113+
114+
$this->qb = $this->getMockBuilder(IQueryBuilder:: class)
115+
->disableOriginalConstructor()
116+
->getMock();
117+
118+
$this->expr = $this->getMockBuilder(IExpressionBuilder:: class)
119+
->disableOriginalConstructor()
120+
->getMock();
121+
122+
123+
$this->qb->method('expr')->willReturn($this->expr);
124+
$this->db->method('getQueryBuilder')->willReturn($this->qb);
125+
126+
127+
$this->mapper = new QBTestMapper($this->db);
128+
}
129+
130+
/**
131+
*
132+
*/
133+
public function testInsertEntityParameterTypeMapping() {
134+
$entity = new QBTestEntity();
135+
$entity->setIntProp(123);
136+
$entity->setBoolProp(true);
137+
$entity->setStringProp('string');
138+
$entity->setIntegerProp(456);
139+
$entity->setBooleanProp(false);
140+
141+
$intParam = $this->qb->createNamedParameter('int_prop', IQueryBuilder::PARAM_INT);
142+
$boolParam = $this->qb->createNamedParameter('bool_prop', IQueryBuilder::PARAM_BOOL);
143+
$stringParam = $this->qb->createNamedParameter('string_prop', IQueryBuilder::PARAM_STR);
144+
$integerParam = $this->qb->createNamedParameter('integer_prop', IQueryBuilder::PARAM_INT);
145+
$booleanParam = $this->qb->createNamedParameter('boolean_prop', IQueryBuilder::PARAM_BOOL);
146+
147+
$this->qb->expects($this->exactly(5))
148+
->method('createNamedParameter')
149+
->withConsecutive(
150+
[$this->equalTo(123), $this->equalTo(IQueryBuilder::PARAM_INT)],
151+
[$this->equalTo(true), $this->equalTo(IQueryBuilder::PARAM_BOOL)],
152+
[$this->equalTo('string'), $this->equalTo(IQueryBuilder::PARAM_STR)],
153+
[$this->equalTo(456), $this->equalTo(IQueryBuilder::PARAM_INT)],
154+
[$this->equalTo(false), $this->equalTo(IQueryBuilder::PARAM_BOOL)]
155+
);
156+
$this->qb->expects($this->exactly(5))
157+
->method('setValue')
158+
->withConsecutive(
159+
[$this->equalTo('int_prop'), $this->equalTo($intParam)],
160+
[$this->equalTo('bool_prop'), $this->equalTo($boolParam)],
161+
[$this->equalTo('string_prop'), $this->equalTo($stringParam)],
162+
[$this->equalTo('integer_prop'), $this->equalTo($integerParam)],
163+
[$this->equalTo('boolean_prop'), $this->equalTo($booleanParam)]
164+
);
165+
166+
$this->mapper->insert($entity);
167+
}
168+
169+
/**
170+
*
171+
*/
172+
public function testUpdateEntityParameterTypeMapping() {
173+
$entity = new QBTestEntity();
174+
$entity->setId(789);
175+
$entity->setIntProp(123);
176+
$entity->setBoolProp('true');
177+
$entity->setStringProp('string');
178+
$entity->setIntegerProp(456);
179+
$entity->setBooleanProp(false);
180+
181+
$idParam = $this->qb->createNamedParameter('id', IQueryBuilder::PARAM_INT);
182+
$intParam = $this->qb->createNamedParameter('int_prop', IQueryBuilder::PARAM_INT);
183+
$boolParam = $this->qb->createNamedParameter('bool_prop', IQueryBuilder::PARAM_BOOL);
184+
$stringParam = $this->qb->createNamedParameter('string_prop', IQueryBuilder::PARAM_STR);
185+
$integerParam = $this->qb->createNamedParameter('integer_prop', IQueryBuilder::PARAM_INT);
186+
$booleanParam = $this->qb->createNamedParameter('boolean_prop', IQueryBuilder::PARAM_BOOL);
187+
188+
$this->qb->expects($this->exactly(6))
189+
->method('createNamedParameter')
190+
->withConsecutive(
191+
[$this->equalTo(123), $this->equalTo(IQueryBuilder::PARAM_INT)],
192+
[$this->equalTo(true), $this->equalTo(IQueryBuilder::PARAM_BOOL)],
193+
[$this->equalTo('string'), $this->equalTo(IQueryBuilder::PARAM_STR)],
194+
[$this->equalTo(456), $this->equalTo(IQueryBuilder::PARAM_INT)],
195+
[$this->equalTo(false), $this->equalTo(IQueryBuilder::PARAM_BOOL)],
196+
[$this->equalTo(789), $this->equalTo(IQueryBuilder::PARAM_INT)]
197+
);
198+
199+
$this->qb->expects($this->exactly(5))
200+
->method('set')
201+
->withConsecutive(
202+
[$this->equalTo('int_prop'), $this->equalTo($intParam)],
203+
[$this->equalTo('bool_prop'), $this->equalTo($boolParam)],
204+
[$this->equalTo('string_prop'), $this->equalTo($stringParam)],
205+
[$this->equalTo('integer_prop'), $this->equalTo($integerParam)],
206+
[$this->equalTo('boolean_prop'), $this->equalTo($booleanParam)]
207+
);
208+
209+
$this->expr->expects($this->once())
210+
->method('eq')
211+
->with($this->equalTo('id'), $this->equalTo($idParam));
212+
213+
214+
$this->mapper->update($entity);
215+
}
216+
217+
/**
218+
*
219+
*/
220+
public function testGetParameterTypeForProperty() {
221+
$entity = new QBTestEntity();
222+
223+
$intType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'intProp');
224+
$this->assertEquals(IQueryBuilder::PARAM_INT, $intType, 'Int type property mapping incorrect');
225+
226+
$integerType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'integerProp');
227+
$this->assertEquals(IQueryBuilder::PARAM_INT, $integerType, 'Integer type property mapping incorrect');
228+
229+
$boolType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'boolProp');
230+
$this->assertEquals(IQueryBuilder::PARAM_BOOL, $boolType, 'Bool type property mapping incorrect');
231+
232+
$booleanType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'booleanProp');
233+
$this->assertEquals(IQueryBuilder::PARAM_BOOL, $booleanType, 'Boolean type property mapping incorrect');
234+
235+
$stringType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'stringProp');
236+
$this->assertEquals(IQueryBuilder::PARAM_STR, $stringType, 'String type property mapping incorrect');
237+
238+
$unknownType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'someProp');
239+
$this->assertEquals(IQueryBuilder::PARAM_STR, $unknownType, 'Unknown type property mapping incorrect');
240+
}
241+
}

0 commit comments

Comments
 (0)