Skip to content

Commit b598f8b

Browse files
committed
Normalise exceptions
1 parent f2cc876 commit b598f8b

10 files changed

+97
-44
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Simply\Database\Exception;
4+
5+
/**
6+
* InvalidRelationshipException.
7+
* @author Riikka Kalliomäki <[email protected]>
8+
* @copyright Copyright (c) 2018 Riikka Kalliomäki
9+
* @license http://opensource.org/licenses/mit-license.php MIT License
10+
*/
11+
class InvalidRelationshipException extends \LogicException
12+
{
13+
14+
}

src/Record.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Simply\Database;
44

5+
use Simply\Database\Exception\InvalidRelationshipException;
6+
57
/**
68
* Record.
79
* @author Riikka Kalliomäki <[email protected]>
@@ -132,7 +134,7 @@ public function getReferencedRecords(string $name): array
132134
$name = $this->getSchema()->getRelationship($name)->getName();
133135

134136
if (!isset($this->referencedRecords[$name])) {
135-
throw new \RuntimeException("The referenced records for the relationship '$name' have not been provided");
137+
throw new \RuntimeException('The referenced records have not been provided');
136138
}
137139

138140
return $this->referencedRecords[$name];
@@ -143,22 +145,22 @@ public function associate(string $name, Model $model): void
143145
$relationship = $this->getSchema()->getRelationship($name);
144146

145147
if (!$relationship->isUniqueRelationship()) {
146-
throw new \InvalidArgumentException('A single model can only be associated to an unique relationships');
148+
throw new InvalidRelationshipException('A single model can only be associated to an unique relationships');
147149
}
148150

149151
$keys = $relationship->getFields();
150152
$fields = $relationship->getReferencedFields();
151153
$record = $model->getDatabaseRecord();
152154

153155
if ($record->getSchema() !== $relationship->getReferencedSchema()) {
154-
throw new \InvalidArgumentException('The associated model has a record with an unexpected schema');
156+
throw new \InvalidArgumentException('The associated record belongs to incorrect schema');
155157
}
156158

157159
while ($keys) {
158160
$value = $record[array_pop($fields)];
159161

160162
if ($value === null) {
161-
throw new \RuntimeException('Cannot associate to models with nulls in referenced fields');
163+
throw new \RuntimeException('Cannot associate with models with nulls in referenced fields');
162164
}
163165

164166
$this[array_pop($keys)] = $value;
@@ -179,7 +181,7 @@ public function addAssociation(string $name, Model $model): void
179181
$relationship = $this->getSchema()->getRelationship($name);
180182

181183
if ($relationship->isUniqueRelationship()) {
182-
throw new \InvalidArgumentException('Cannot add a new model to an unique relationship');
184+
throw new InvalidRelationshipException('Cannot add a new model to an unique relationship');
183185
}
184186

185187
$model->getDatabaseRecord()->associate($relationship->getReverseRelationship()->getName(), $this->getModel());
@@ -190,7 +192,7 @@ public function getRelatedModel(string $name): ?Model
190192
$relationship = $this->getSchema()->getRelationship($name);
191193

192194
if (!$relationship->isUniqueRelationship()) {
193-
throw new \RuntimeException('A single related model can only be fetched for an unique relationship');
195+
throw new InvalidRelationshipException('A single model can only be fetched for an unique relationship');
194196
}
195197

196198
$records = $this->getReferencedRecords($name);
@@ -207,7 +209,7 @@ public function getRelatedModels(string $name): array
207209
$relationship = $this->getSchema()->getRelationship($name);
208210

209211
if ($relationship->isUniqueRelationship()) {
210-
throw new \RuntimeException('Cannot fetch multiple models for an unique relationship');
212+
throw new InvalidRelationshipException('Cannot fetch multiple models for an unique relationship');
211213
}
212214

213215
$models = [];
@@ -225,11 +227,11 @@ public function getRelatedModelsByProxy(string $proxy, string $name): array
225227
$relationship = $proxyRelationship->getReferencedSchema()->getRelationship($name);
226228

227229
if ($proxyRelationship->isUniqueRelationship()) {
228-
throw new \RuntimeException('Cannot fetch related models via an unique proxy relationship');
230+
throw new InvalidRelationshipException('Cannot fetch models via an unique proxy relationship');
229231
}
230232

231233
if (!$relationship->isUniqueRelationship()) {
232-
throw new \RuntimeException('Related models can only be fetched via proxy with an unique relationship');
234+
throw new InvalidRelationshipException('Cannot fetch models via proxy without a unique relationship');
233235
}
234236

235237
$models = [];

src/Relationship.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Simply\Database;
44

5+
use Simply\Database\Exception\InvalidRelationshipException;
6+
57
/**
68
* Relation.
79
* @author Riikka Kalliomäki <[email protected]>
@@ -113,10 +115,10 @@ function (Relationship $relationship): bool {
113115

114116
if (\count($reverse) !== 1) {
115117
if (\count($reverse) > 1) {
116-
throw new \RuntimeException('Multiple reverse relationship exists for this relationship');
118+
throw new InvalidRelationshipException('Multiple reverse relationship exists for this relationship');
117119
}
118120

119-
throw new \RuntimeException('No reverse relationship exists for this relationship');
121+
throw new InvalidRelationshipException('No reverse relationship exists for this relationship');
120122
}
121123

122124
return array_pop($reverse);
@@ -137,7 +139,7 @@ private function isReverseRelationship(Relationship $relationship): bool
137139
public function fillRelationship(array $records, array $referencedRecords): void
138140
{
139141
if (\count($this->getFields()) !== 1) {
140-
throw new \RuntimeException('Relationship fill is not supported for composite foreign keys');
142+
throw new InvalidRelationshipException('Relationship fill is not supported for composite foreign keys');
141143
}
142144

143145
if (empty($records)) {
@@ -170,7 +172,7 @@ private function getSortedRecords(array $records): array
170172
}
171173

172174
if ($unique && isset($sorted[$value])) {
173-
throw new \InvalidArgumentException('Unique relationship cannot reference more than a single record');
175+
throw new InvalidRelationshipException('Multiple records detected for unique relationship');
174176
}
175177

176178
$sorted[$value][] = $record;
@@ -212,7 +214,7 @@ private function assignSortedRecords(array $records, array $sorted): void
212214
public function fillSingleRecord(Record $record, Record $referencedRecord): void
213215
{
214216
if (!$this->isUniqueRelationship()) {
215-
throw new \LogicException('Only unique relationships can be filled with single records');
217+
throw new InvalidRelationshipException('Only unique relationships can be filled with single records');
216218
}
217219

218220
if ($referencedRecord->isEmpty()) {
@@ -225,7 +227,7 @@ public function fillSingleRecord(Record $record, Record $referencedRecord): void
225227

226228
while ($keys) {
227229
if ((string) $record[array_pop($keys)] !== (string) $referencedRecord[array_pop($fields)]) {
228-
throw new \LogicException('Tried to fill a record with a record that is not the referenced record');
230+
throw new \InvalidArgumentException('The provided records are not related');
229231
}
230232
}
231233

src/RelationshipFiller.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Simply\Database;
44

55
use Simply\Database\Connection\Connection;
6+
use Simply\Database\Exception\InvalidRelationshipException;
67

78
/**
89
* RelationshipFiller.
@@ -66,7 +67,7 @@ private function fillRelationships(array $records, array $relationships): void
6667
$schemaId = $this->getSchemaId($parent);
6768

6869
if (\count($fields) > 1) {
69-
throw new \InvalidArgumentException('Filling relationships for composite foreign keys is not supported');
70+
throw new InvalidRelationshipException('Composite foreign keys are not supported by batch fill');
7071
}
7172

7273
$isPrimaryReference = $fields === $parent->getPrimaryKey();
@@ -165,4 +166,4 @@ private function getSchemaId(Schema $schema): int
165166
{
166167
return spl_object_id($schema);
167168
}
168-
}
169+
}

src/Repository.php

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,15 @@ protected function find(Schema $schema, array $conditions, array $order = [], in
3535
return $models;
3636
}
3737

38-
protected function findOne(Schema $schema, array $conditions): ?Model
38+
protected function findOne(Schema $schema, array $conditions, array $order = []): ?Model
3939
{
40-
$keys = $schema->getPrimaryKey();
41-
$order = array_fill_keys($keys, Connection::ORDER_ASCENDING);
40+
if ($order === []) {
41+
$keys = $schema->getPrimaryKey();
42+
$order = array_fill_keys($keys, Connection::ORDER_ASCENDING);
43+
}
4244

4345
$result = $this->connection->select($schema->getFields(), $schema->getTable(), $conditions, $order, 1);
44-
$result->setFetchMode(\PDO::FETCH_ASSOC);
45-
$row = $result->fetch();
46+
$row = $result->fetch(\PDO::FETCH_ASSOC);
4647

4748
return $row ? $schema->createModelFromRow($row) : null;
4849
}
@@ -54,15 +55,24 @@ protected function findOne(Schema $schema, array $conditions): ?Model
5455
*/
5556
protected function findByPrimaryKey(Schema $schema, $values): ?Model
5657
{
57-
return $this->findOne($schema, $this->getPrimaryKeyCondition($schema, $values));
58+
$conditions = $this->getPrimaryKeyCondition($schema, $values);
59+
60+
$result = $this->connection->select($schema->getFields(), $schema->getTable(), $conditions);
61+
$rows = $result->fetchAll(\PDO::FETCH_ASSOC);
62+
63+
if (\count($rows) > 1) {
64+
throw new \UnexpectedValueException('Unexpected number of results returned by primary key');
65+
}
66+
67+
return $rows ? $schema->createModelFromRow(reset($rows)) : null;
5868
}
5969

6070
/**
6171
* @param Schema $schema
6272
* @param mixed $values
6373
* @return array
6474
*/
65-
protected function getPrimaryKeyCondition(Schema $schema, $values): array
75+
private function getPrimaryKeyCondition(Schema $schema, $values): array
6676
{
6777
$keys = $schema->getPrimaryKey();
6878
$condition = [];
@@ -137,13 +147,13 @@ protected function refresh(Model $model): void
137147
$schema = $record->getSchema();
138148

139149
$result = $this->connection->select($schema->getFields(), $schema->getTable(), $record->getPrimaryKey());
140-
$row = $result->fetch(\PDO::FETCH_ASSOC);
150+
$rows = $result->fetchAll(\PDO::FETCH_ASSOC);
141151

142-
if (empty($row)) {
152+
if (\count($rows) !== 1) {
143153
throw new MissingRecordException('Tried to refresh a record that does not exist in the database');
144154
}
145155

146-
$record->setDatabaseValues($row);
156+
$record->setDatabaseValues(reset($rows));
147157
}
148158

149159
protected function update(Model $model): void

src/Schema.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Simply\Database;
44

55
use Psr\Container\ContainerInterface;
6+
use Simply\Database\Exception\InvalidRelationshipException;
67

78
/**
89
* Schema.
@@ -65,7 +66,7 @@ public function getRelationship(string $name): Relationship
6566
$definition = $this->getRelationshipDefinitions()[$name] ?? null;
6667

6768
if (empty($definition)) {
68-
throw new \InvalidArgumentException("Invalid relationship '$name'");
69+
throw new InvalidRelationshipException("Undefined relationship '$name'");
6970
}
7071

7172
$key = \is_array($definition['key']) ? $definition['key'] : [$definition['key']];

tests/tests/RecordTest.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Simply\Database;
44

5+
use Simply\Database\Exception\InvalidRelationshipException;
56
use Simply\Database\Test\TestCase\UnitTestCase;
67

78
/**
@@ -37,7 +38,7 @@ public function testMultipleModelAssociation(): void
3738
$personA = $schema->createRecord();
3839
$personB = $schema->createRecord();
3940

40-
$this->expectException(\InvalidArgumentException::class);
41+
$this->expectException(InvalidRelationshipException::class);
4142
$personA->associate('parents', $personB->getModel());
4243
}
4344

@@ -70,7 +71,7 @@ public function testAddAssociationToUniqueRelationship(): void
7071
$personA = $schema->createRecord();
7172
$personB = $schema->createRecord();
7273

73-
$this->expectException(\InvalidArgumentException::class);
74+
$this->expectException(InvalidRelationshipException::class);
7475
$personA->addAssociation('spouse', $personB->getModel());
7576
}
7677

@@ -101,7 +102,7 @@ public function testGetRelatedModelForNonUnique(): void
101102
$schema = $this->getPersonSchema();
102103
$person = $schema->createRecord();
103104

104-
$this->expectException(\RuntimeException::class);
105+
$this->expectException(InvalidRelationshipException::class);
105106
$person->getRelatedModel('parents');
106107
}
107108

@@ -120,7 +121,7 @@ public function testGetMultipleModelsForNonUnique(): void
120121
$schema = $this->getPersonSchema();
121122
$person = $schema->createRecord();
122123

123-
$this->expectException(\RuntimeException::class);
124+
$this->expectException(InvalidRelationshipException::class);
124125
$person->getRelatedModels('spouse');
125126
}
126127

@@ -184,15 +185,15 @@ public function testInvalidProxyRelation(): void
184185
{
185186
$person = $this->getPersonSchema()->createRecord();
186187

187-
$this->expectException(\RuntimeException::class);
188+
$this->expectException(InvalidRelationshipException::class);
188189
$person->getRelatedModelsByProxy('spouse', 'spouse');
189190
}
190191

191192
public function testInvalidProxiedRelation(): void
192193
{
193194
$house = $this->getPersonSchema()->getRelationship('home')->getReferencedSchema()->createRecord();
194195

195-
$this->expectException(\RuntimeException::class);
196+
$this->expectException(InvalidRelationshipException::class);
196197
$house->getRelatedModelsByProxy('residents', 'parents');
197198
}
198199

@@ -211,4 +212,4 @@ public function testEmptyProxy(): void
211212

212213
$this->assertSame([], $person->getRelatedModelsByProxy('parents', 'parent'));
213214
}
214-
}
215+
}

tests/tests/RelationshipFillerTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Simply\Database;
44

55
use Simply\Database\Connection\Connection;
6+
use Simply\Database\Exception\InvalidRelationshipException;
67
use Simply\Database\Test\TestCase\UnitTestCase;
78

89
/**
@@ -56,7 +57,7 @@ public function testFillingWithCompositeForeignKeys(): void
5657
$connection = $this->createMock(Connection::class);
5758
$filler = new RelationshipFiller($connection);
5859

59-
$this->expectException(\InvalidArgumentException::class);
60+
$this->expectException(InvalidRelationshipException::class);
6061
$filler->fill([$order], ['replaced']);
6162
}
6263

@@ -99,4 +100,4 @@ public function testNoQueriesWhenCached()
99100
$connection->expects($this->never())->method('select');
100101
$filler->fill([$personA, $personB], ['spouse']);
101102
}
102-
}
103+
}

tests/tests/RepositoryTest.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,24 @@ public function testInvalidPrimaryKeyValue(): void
4242
$this->expectException(\InvalidArgumentException::class);
4343
$method->invoke($repository, $schema, [1, [2, 3]]);
4444
}
45-
}
45+
46+
public function testMultipleRecordsByPrimaryKey(): void
47+
{
48+
$result = $this->createMock(\PDOStatement::class);
49+
$result->expects($this->once())->method('fetchAll')->willReturn([['id' => 1], ['id' => 1]]);
50+
51+
$connection = $this->createMock(Connection::class);
52+
$connection->expects($this->once())->method('select')->willReturn($result);
53+
54+
$repository = new class($connection) extends Repository {
55+
};
56+
57+
$schema = $this->getPersonSchema();
58+
59+
$method = new \ReflectionMethod($repository, 'findByPrimaryKey');
60+
$method->setAccessible(true);
61+
62+
$this->expectException(\UnexpectedValueException::class);
63+
$method->invoke($repository, $schema, 1);
64+
}
65+
}

0 commit comments

Comments
 (0)