Skip to content

Commit 4f47926

Browse files
committed
feature: php object query
for #84
1 parent 0422a5c commit 4f47926

File tree

7 files changed

+180
-33
lines changed

7 files changed

+180
-33
lines changed

src/Database.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class Database {
2525
/** @var array<Driver> */
2626
protected array $driverArray;
2727
protected Connection $currentConnectionName;
28+
protected string $appNamespace = "\\App";
2829

2930
public function __construct(SettingsInterface...$connectionSettings) {
3031
if(empty($connectionSettings)) {
@@ -36,6 +37,14 @@ public function __construct(SettingsInterface...$connectionSettings) {
3637
$this->storeQueryCollectionFactoryFromSettings($connectionSettings);
3738
}
3839

40+
public function setAppNameSpace(string $namespace):void {
41+
if(!str_starts_with($namespace, "\\")) {
42+
$namespace = "\\$namespace";
43+
}
44+
45+
$this->appNamespace = $namespace;
46+
}
47+
3948
public function insert(string $queryName, mixed...$bindings):string {
4049
$result = $this->query($queryName, $bindings);
4150
return $result->lastInsertId();

src/Query/PhpQuery.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
use Gt\Database\Connection\Driver;
55

66
class PhpQuery extends Query {
7+
private string $className;
78
private string $functionName;
9+
private string $appNamespace = "\\App\\Query";
10+
private mixed $instance;
811

912
public function __construct(string $filePathWithFunction, Driver $driver) {
1013
[$filePath, $functionName] = explode("::", $filePathWithFunction);
@@ -14,12 +17,32 @@ public function __construct(string $filePathWithFunction, Driver $driver) {
1417
}
1518

1619
$this->filePath = $filePath;
20+
$this->className = pathinfo($filePath, PATHINFO_FILENAME);
1721
$this->functionName = $functionName;
1822
$this->connection = $driver->getConnection();
23+
24+
require_once($filePath);
25+
}
26+
27+
public function setAppNamespace(string $namespace):void {
28+
if(!str_starts_with($namespace, "\\")) {
29+
$namespace = "\\$namespace";
30+
}
31+
32+
$this->appNamespace = $namespace;
1933
}
2034

2135
/** @param array<string, mixed>|array<mixed> $bindings */
2236
public function getSql(array &$bindings = []):string {
23-
// TODO: Include similarly to page logic files, with optional namespacing (I think...)
37+
$fqClassName = $this->appNamespace . "\\" . $this->className;
38+
if(!class_exists($fqClassName)) {
39+
throw new PhpQueryClassNotFoundException($fqClassName);
40+
}
41+
42+
if(!isset($this->instance)) {
43+
$this->instance = new $fqClassName();
44+
}
45+
46+
return $this->instance->{$this->functionName}();
2447
}
2548
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
namespace Gt\Database\Query;
3+
4+
use Gt\Database\DatabaseException;
5+
6+
class PhpQueryClassNotFoundException extends DatabaseException {
7+
}

src/Query/Query.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ abstract class Query {
1717

1818
protected string $filePath;
1919
protected Connection $connection;
20-
21-
20+
protected ?string $namespace = null;
2221

2322
public function getFilePath():string {
2423
return $this->filePath;

src/Query/QueryCollection.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ abstract class QueryCollection {
1010

1111
protected string $directoryPath;
1212
protected QueryFactory $queryFactory;
13+
protected string $appNamespace = "\\App\\Query";
1314

1415
public function __construct(
1516
string $directoryPath,
@@ -23,6 +24,14 @@ public function __construct(
2324
);
2425
}
2526

27+
public function setAppNamespace(string $namespace):void {
28+
if(!str_starts_with($namespace, "\\")) {
29+
$namespace = "\\$namespace";
30+
}
31+
32+
$this->appNamespace = $namespace;
33+
}
34+
2635
/** @param array<mixed> $args */
2736
public function __call(string $name, array $args):ResultSet {
2837
if(isset($args[0]) && is_array($args[0])) {
@@ -40,6 +49,10 @@ public function query(
4049
mixed...$placeholderMap
4150
):ResultSet {
4251
$query = $this->queryFactory->create($name);
52+
if($query instanceof PhpQuery) {
53+
$query->setAppNamespace($this->appNamespace);
54+
}
55+
4356
return $query->execute($placeholderMap);
4457
}
4558

src/Query/QueryCollectionClass.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
<?php
22
namespace Gt\Database\Query;
33

4-
use Gt\Database\Query\QueryCollection;
5-
64
class QueryCollectionClass extends QueryCollection {
75
}
Lines changed: 126 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22
namespace Gt\Database\Test\Query;
33

4+
use DateTime;
45
use Gt\Database\Connection\DefaultSettings;
56
use Gt\Database\Connection\Driver;
67
use Gt\Database\Query\PhpQuery;
@@ -14,36 +15,28 @@
1415
use PHPUnit\Framework\TestCase;
1516

1617
class QueryCollectionTest extends TestCase {
17-
/** @var QueryCollection */
18-
private $queryCollection;
19-
/** @var MockObject|Query */
20-
private $mockQuery;
21-
22-
protected function setUp():void {
23-
/** @var MockObject|QueryFactory $mockQueryFactory */
24-
$mockQueryFactory = $this->createMock(QueryFactory::class);
25-
$this->mockQuery = $this->createMock(Query::class);
26-
$mockQueryFactory
18+
public function testQueryCollectionQuery() {
19+
$queryFactory = $this->createMock(QueryFactory::class);
20+
$query = $this->createMock(Query::class);
21+
$queryFactory
2722
->expects(static::once())
2823
->method("create")
2924
->with("something")
30-
->willReturn($this->mockQuery);
25+
->willReturn($query);
3126

32-
$this->queryCollection = new QueryCollectionDirectory(
27+
$queryCollection = new QueryCollectionDirectory(
3328
__DIR__,
3429
new Driver(new DefaultSettings()),
35-
$mockQueryFactory
30+
$queryFactory
3631
);
37-
}
3832

39-
public function testQueryCollectionQuery() {
4033
$placeholderVars = ["nombre" => "hombre"];
41-
$this->mockQuery
34+
$query
4235
->expects(static::once())
4336
->method("execute")
4437
->with([$placeholderVars]);
4538

46-
$resultSet = $this->queryCollection->query(
39+
$resultSet = $queryCollection->query(
4740
"something",
4841
$placeholderVars
4942
);
@@ -55,9 +48,23 @@ public function testQueryCollectionQuery() {
5548
}
5649

5750
public function testQueryCollectionQueryNoParams() {
58-
$this->mockQuery->expects(static::once())->method("execute")->with();
51+
$queryFactory = $this->createMock(QueryFactory::class);
52+
$query = $this->createMock(Query::class);
53+
$queryFactory
54+
->expects(static::once())
55+
->method("create")
56+
->with("something")
57+
->willReturn($query);
58+
59+
$queryCollection = new QueryCollectionDirectory(
60+
__DIR__,
61+
new Driver(new DefaultSettings()),
62+
$queryFactory
63+
);
64+
65+
$query->expects(static::once())->method("execute")->with();
5966

60-
$resultSet = $this->queryCollection->query("something");
67+
$resultSet = $queryCollection->query("something");
6168

6269
static::assertInstanceOf(
6370
ResultSet::class,
@@ -66,28 +73,56 @@ public function testQueryCollectionQueryNoParams() {
6673
}
6774

6875
public function testQueryShorthand() {
76+
$queryFactory = $this->createMock(QueryFactory::class);
77+
$query = $this->createMock(Query::class);
78+
$queryFactory
79+
->expects(static::once())
80+
->method("create")
81+
->with("something")
82+
->willReturn($query);
83+
84+
$queryCollection = new QueryCollectionDirectory(
85+
__DIR__,
86+
new Driver(new DefaultSettings()),
87+
$queryFactory
88+
);
89+
6990
$placeholderVars = ["nombre" => "hombre"];
70-
$this->mockQuery
91+
$query
7192
->expects(static::once())
7293
->method("execute")
7394
->with([$placeholderVars]);
7495

7596
static::assertInstanceOf(
7697
ResultSet::class,
77-
$this->queryCollection->something($placeholderVars)
98+
$queryCollection->something($placeholderVars)
7899
);
79100
}
80101

81102
public function testQueryShorthandNoParams() {
82-
$this->mockQuery->expects(static::once())->method("execute")->with();
103+
$queryFactory = $this->createMock(QueryFactory::class);
104+
$query = $this->createMock(Query::class);
105+
$queryFactory
106+
->expects(static::once())
107+
->method("create")
108+
->with("something")
109+
->willReturn($query);
110+
111+
$queryCollection = new QueryCollectionDirectory(
112+
__DIR__,
113+
new Driver(new DefaultSettings()),
114+
$queryFactory
115+
);
116+
117+
$query->expects(static::once())->method("execute")->with();
83118

84119
static::assertInstanceOf(
85120
ResultSet::class,
86-
$this->queryCollection->something()
121+
$queryCollection->something()
87122
);
88123
}
89124

90-
public function testQueryCollectionClass() {
125+
public function testQueryCollectionClass_defaultNamespace() {
91126
$projectDir = implode(DIRECTORY_SEPARATOR, [
92127
sys_get_temp_dir(),
93128
"phpgt",
@@ -96,20 +131,83 @@ public function testQueryCollectionClass() {
96131
]);
97132
$baseQueryDirectory = implode(DIRECTORY_SEPARATOR, [
98133
$projectDir,
99-
"query",
134+
"resultSet",
100135
]);
101136
$queryCollectionClassPath = "$baseQueryDirectory/Example.php";
102137
if(!is_dir($baseQueryDirectory)) {
103138
mkdir($baseQueryDirectory, recursive: true);
104139
}
105-
touch($queryCollectionClassPath);
140+
$php = <<<PHP
141+
<?php
142+
namespace App\Query;
143+
144+
class Example {
145+
public function getTimestamp():string {
146+
return "select current_timestamp";
147+
}
148+
}
149+
PHP;
150+
151+
file_put_contents($queryCollectionClassPath, $php);
106152

107153
$sut = new QueryCollectionClass(
108154
$queryCollectionClassPath,
109155
new Driver(new DefaultSettings()),
110156
);
111157

112-
$query = $sut->query("getTimestamp");
113-
self::assertInstanceOf(PhpQuery::class, $query);
158+
$resultSet = $sut->query("getTimestamp");
159+
self::assertInstanceOf(ResultSet::class, $resultSet);
160+
$row = $resultSet->fetch();
161+
$actualDateTime = $row->getDateTime("current_timestamp");
162+
$expectedDateTime = new DateTime();
163+
self::assertSame(
164+
$expectedDateTime->format("Y-m-d H:i"),
165+
$actualDateTime->format("Y-m-d H:i"),
166+
);
167+
}
168+
169+
public function testQueryCollectionClass_namespace() {
170+
$projectDir = implode(DIRECTORY_SEPARATOR, [
171+
sys_get_temp_dir(),
172+
"phpgt",
173+
"database",
174+
uniqid(),
175+
]);
176+
$baseQueryDirectory = implode(DIRECTORY_SEPARATOR, [
177+
$projectDir,
178+
"resultSet",
179+
]);
180+
$queryCollectionClassPath = "$baseQueryDirectory/Example.php";
181+
if(!is_dir($baseQueryDirectory)) {
182+
mkdir($baseQueryDirectory, recursive: true);
183+
}
184+
$php = <<<PHP
185+
<?php
186+
namespace GtTest\DatabaseExample;
187+
188+
class Example {
189+
public function getTimestamp():string {
190+
return "select current_timestamp";
191+
}
192+
}
193+
PHP;
194+
195+
file_put_contents($queryCollectionClassPath, $php);
196+
197+
$sut = new QueryCollectionClass(
198+
$queryCollectionClassPath,
199+
new Driver(new DefaultSettings()),
200+
);
201+
$sut->setAppNamespace("GtTest\\DatabaseExample");
202+
203+
$resultSet = $sut->query("getTimestamp");
204+
self::assertInstanceOf(ResultSet::class, $resultSet);
205+
$row = $resultSet->fetch();
206+
$actualDateTime = $row->getDateTime("current_timestamp");
207+
$expectedDateTime = new DateTime();
208+
self::assertSame(
209+
$expectedDateTime->format("Y-m-d H:i"),
210+
$actualDateTime->format("Y-m-d H:i"),
211+
);
114212
}
115213
}

0 commit comments

Comments
 (0)