Skip to content

Commit a4f0eca

Browse files
committed
Sync: review SqlQuery and DbSyncProvider classes
1 parent 1f37c9d commit a4f0eca

File tree

4 files changed

+78
-96
lines changed

4 files changed

+78
-96
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -375,46 +375,6 @@ parameters:
375375
count: 1
376376
path: src/Support/ProviderContext.php
377377

378-
-
379-
message: "#^Method Lkrms\\\\Support\\\\SqlQuery\\:\\:addNextParam\\(\\) has parameter \\$value with no type specified\\.$#"
380-
count: 1
381-
path: src/Support/SqlQuery.php
382-
383-
-
384-
message: "#^Method Lkrms\\\\Support\\\\SqlQuery\\:\\:addParam\\(\\) has parameter \\$value with no type specified\\.$#"
385-
count: 1
386-
path: src/Support/SqlQuery.php
387-
388-
-
389-
message: "#^Method Lkrms\\\\Support\\\\SqlQuery\\:\\:buildWhere\\(\\) has no return type specified\\.$#"
390-
count: 1
391-
path: src/Support/SqlQuery.php
392-
393-
-
394-
message: "#^Method Lkrms\\\\Support\\\\SqlQuery\\:\\:buildWhere\\(\\) has parameter \\$where with no value type specified in iterable type array\\.$#"
395-
count: 1
396-
path: src/Support/SqlQuery.php
397-
398-
-
399-
message: "#^Method Lkrms\\\\Support\\\\SqlQuery\\:\\:getWhere\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#"
400-
count: 1
401-
path: src/Support/SqlQuery.php
402-
403-
-
404-
message: "#^Method Lkrms\\\\Support\\\\SqlQuery\\:\\:where\\(\\) has parameter \\$clause with no value type specified in iterable type array\\.$#"
405-
count: 1
406-
path: src/Support/SqlQuery.php
407-
408-
-
409-
message: "#^Method Lkrms\\\\Support\\\\SqlQuery\\:\\:whereValueInList\\(\\) has parameter \\$value with no type specified\\.$#"
410-
count: 1
411-
path: src/Support/SqlQuery.php
412-
413-
-
414-
message: "#^Property Lkrms\\\\Support\\\\SqlQuery\\:\\:\\$Where type has no value type specified in iterable type array\\.$#"
415-
count: 1
416-
path: src/Support/SqlQuery.php
417-
418378
-
419379
message: "#^Property Lkrms\\\\Sync\\\\Support\\\\SyncEntityProvider\\:\\:\\$Offline is never read, only written\\.$#"
420380
count: 1

src/Support/SqlQuery.php

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use Lkrms\Concept\FluentInterface;
66
use Lkrms\Concern\TReadable;
77
use Lkrms\Contract\IReadable;
8-
use UnexpectedValueException;
8+
use LogicException;
99

1010
/**
1111
* A simple representation of a SQL query
@@ -20,21 +20,23 @@ final class SqlQuery extends FluentInterface implements IReadable
2020
public const OR = 'OR';
2121

2222
/**
23-
* A list of optionally nested WHERE clauses
23+
* A list of optionally nested WHERE conditions
2424
*
25-
* To join a list of clauses with an explicit operator:
25+
* To join a list of conditions with an explicit operator:
2626
*
2727
* ```php
28+
* <?php
2829
* [
2930
* '__' => SqlQuery::AND,
3031
* 'Id = ?',
3132
* 'Deleted IS NULL',
3233
* ]
3334
* ```
3435
*
35-
* To use nested clauses:
36+
* To use nested conditions:
3637
*
3738
* ```php
39+
* <?php
3840
* [
3941
* '__' => SqlQuery::AND,
4042
* 'ItemKey = ?',
@@ -46,7 +48,7 @@ final class SqlQuery extends FluentInterface implements IReadable
4648
* ]
4749
* ```
4850
*
49-
* @var array<int|string,string|array>
51+
* @var array<int|string,string|mixed[]>
5052
*/
5153
public $Where = [];
5254

@@ -58,21 +60,23 @@ final class SqlQuery extends FluentInterface implements IReadable
5860
protected $Values = [];
5961

6062
/**
61-
* @var callable
63+
* @var callable(string): string
6264
*/
6365
protected $ParamCallback;
6466

67+
/**
68+
* @inheritDoc
69+
*/
6570
public static function getReadable(): array
6671
{
6772
return ['Values'];
6873
}
6974

7075
/**
71-
* @param callable $paramCallback Applied to the name of each parameter
72-
* added to the query.
73-
* ```php
74-
* function (string $name): string
75-
* ```
76+
* Creates a new SqlQuery object
77+
*
78+
* @param callable(string): string $paramCallback Applied to the name of
79+
* each parameter added to the query.
7680
*/
7781
public function __construct(callable $paramCallback)
7882
{
@@ -82,12 +86,13 @@ public function __construct(callable $paramCallback)
8286
/**
8387
* Add a parameter and assign its query placeholder to a variable
8488
*
89+
* @param mixed $value
8590
* @return $this
8691
*/
8792
public function addParam(string $name, $value, ?string &$placeholder)
8893
{
8994
if (array_key_exists($name, $this->Values)) {
90-
throw new UnexpectedValueException("Parameter already added: $name");
95+
throw new LogicException(sprintf('Parameter already added: %s', $name));
9196
}
9297

9398
$placeholder = ($this->ParamCallback)($name);
@@ -97,73 +102,85 @@ public function addParam(string $name, $value, ?string &$placeholder)
97102
}
98103

99104
/**
100-
* Add a WHERE clause
105+
* Add a WHERE condition
101106
*
102-
* See {@see SqlQuery::$Where}.
107+
* @see SqlQuery::$Where
103108
*
104-
* @param callable|string|array $clause A string, an array, or a callback
105-
* that returns a string or array.
106-
* ```php
107-
* fn(): string|array
108-
* ```
109+
* @param (callable(): (string|mixed[]))|string|mixed[] $condition
109110
* @return $this
110111
*/
111-
public function where($clause)
112+
public function where($condition)
112113
{
113-
$this->Where[] = is_callable($clause) ? $clause() : $clause;
114+
$this->Where[] = is_callable($condition) ? $condition() : $condition;
114115

115116
return $this;
116117
}
117118

118119
/**
119-
* Add "<name> IN (<value>[,<value>])" to the query unless a list of values
120-
* is empty
120+
* Add a list of values as a WHERE condition ("<name> IN (<value>...)")
121+
* unless the list is empty
121122
*
123+
* @param mixed ...$value
122124
* @return $this
123125
*/
124126
public function whereValueInList(string $name, ...$value)
125127
{
126-
if (!count($value)) {
128+
if (!$value) {
127129
return $this;
128130
}
129131

130-
$expr = [];
131-
foreach ($value as $_value) {
132-
$expr[] = $this->addNextParam($_value);
132+
foreach ($value as $val) {
133+
$expr[] = $this->addNextParam($val);
133134
}
134135
$this->Where[] = "$name IN (" . implode(',', $expr) . ')';
135136

136137
return $this;
137138
}
138139

140+
/**
141+
* Prepare a WHERE condition for use in a SQL statement
142+
*
143+
* @param array<string,mixed>|null $values
144+
*/
139145
public function getWhere(?array &$values = null): ?string
140146
{
141147
$values = $this->Values;
148+
$where = $this->buildWhere($this->Where);
142149

143-
return $this->buildWhere($this->Where) ?: null;
150+
return $where === ''
151+
? null
152+
: $where;
144153
}
145154

155+
/**
156+
* @param mixed $value
157+
*/
146158
private function addNextParam($value): string
147159
{
148160
$this->addParam('param_' . count($this->Values), $value, $param);
149161

150162
return $param;
151163
}
152164

153-
private function buildWhere(array $where)
165+
/**
166+
* @param array<int|string,string|mixed[]> $where
167+
*/
168+
private function buildWhere(array $where): string
154169
{
155170
$glue = $where['__'] ?? self::AND;
156171
unset($where['__']);
157-
foreach ($where as $i => $clause) {
158-
if (is_array($clause)) {
159-
if (!($clause = $this->buildWhere($clause))) {
172+
foreach ($where as $i => $condition) {
173+
if (is_array($condition)) {
174+
$condition = $this->buildWhere($condition);
175+
if ($condition === '') {
160176
unset($where[$i]);
161177
continue;
162178
}
163-
$where[$i] = "($clause)";
179+
$where[$i] = "($condition)";
164180
}
165181
}
166182

183+
/** @var string[] $where */
167184
return implode(" $glue ", $where);
168185
}
169186
}

src/Sync/Concept/DbSyncProvider.php

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,24 @@
1919
*/
2020
abstract class DbSyncProvider extends SyncProvider
2121
{
22-
/**
23-
* @var DbConnector|null
24-
*/
25-
private $DbConnector;
26-
27-
/**
28-
* @var ADOConnection|null
29-
*/
30-
private $Db;
22+
private DbConnector $DbConnector;
23+
private ADOConnection $Db;
3124

3225
/**
33-
* Specify how to connect to the upstream database
26+
* Specify how to connect to the backend
3427
*
3528
* The {@see DbConnector} returned will be cached for the lifetime of the
3629
* {@see DbSyncProvider} instance.
3730
*
3831
*/
39-
abstract protected function getNewDbConnector(): DbConnector;
32+
abstract protected function getDbConnector(): DbConnector;
4033

4134
/**
4235
* @inheritDoc
4336
*/
4437
public function getBackendIdentifier(): array
4538
{
46-
$connector = $this->getDbConnector();
39+
$connector = $this->dbConnector();
4740
if ($connector->Dsn) {
4841
/** @todo Implement DSN parsing */
4942
throw new RuntimeException('DSN parsing not implemented');
@@ -61,6 +54,8 @@ public function getBackendIdentifier(): array
6154
}
6255

6356
/**
57+
* @inheritDoc
58+
*
6459
* @template T of ISyncEntity
6560
* @param class-string<T> $entity
6661
* @return ISyncDefinition<T,static>
@@ -80,34 +75,43 @@ final public function getDefinition(string $entity): ISyncDefinition
8075
return $def;
8176
}
8277

83-
final public function getDbConnector(): DbConnector
78+
/**
79+
* Get a DbConnector instance to open connections to the backend
80+
*/
81+
final public function dbConnector(): DbConnector
8482
{
8583
return $this->DbConnector
86-
?: ($this->DbConnector = $this->getNewDbConnector());
84+
?? ($this->DbConnector = $this->getDbConnector());
8785
}
8886

87+
/**
88+
* Get a connection to the backend
89+
*/
8990
final public function getDb(): ADOConnection
9091
{
91-
if (!$this->Db) {
92+
if (!isset($this->Db)) {
9293
Assert::localeIsUtf8();
9394

94-
return $this->Db = $this->getDbConnector()->getConnection();
95+
return $this->Db = $this->dbConnector()->getConnection();
9596
}
9697

9798
return $this->Db;
9899
}
99100

101+
/**
102+
* Get a SqlQuery instance to prepare queries for the backend
103+
*/
100104
final public function getSqlQuery(ADOConnection $db): SqlQuery
101105
{
102-
return new SqlQuery(fn($name) => $db->Param($name));
106+
return new SqlQuery(fn(string $name): string => $db->Param($name));
103107
}
104108

109+
/**
110+
* @inheritDoc
111+
*/
105112
public function checkHeartbeat(int $ttl = 300)
106113
{
107-
$this
108-
->getDbConnector()
109-
->getConnection(5);
110-
114+
$this->dbConnector()->getConnection(5);
111115
return $this;
112116
}
113117

@@ -124,8 +128,7 @@ public function checkHeartbeat(int $ttl = 300)
124128
* @return DbSyncDefinitionBuilder<T,static>
125129
*/
126130
protected function buildDbDefinition(
127-
string $entity,
128-
DbSyncDefinitionBuilder $defB
131+
string $entity, DbSyncDefinitionBuilder $defB
129132
): DbSyncDefinitionBuilder {
130133
return $defB;
131134
}

src/Sync/Concept/HttpSyncProvider.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ final public function getCurler(
7171
}
7272

7373
/**
74+
* @inheritDoc
75+
*
7476
* @template T of ISyncEntity
7577
* @param class-string<T> $entity
7678
* @return ISyncDefinition<T,static>

0 commit comments

Comments
 (0)