@@ -16,12 +16,15 @@ class Record implements \ArrayAccess
16
16
17
17
private $ schema ;
18
18
19
+ private $ primaryKey ;
20
+
19
21
private $ values ;
20
22
21
23
private $ changed ;
22
24
23
25
private $ state ;
24
26
27
+ /** @var Record[][] */
25
28
private $ relations ;
26
29
27
30
public function __construct (Schema $ schema )
@@ -30,17 +33,16 @@ public function __construct(Schema $schema)
30
33
$ this ->values = array_fill_keys ($ schema ->getFields (), null );
31
34
$ this ->state = self ::STATE_INSERT ;
32
35
$ this ->changed = [];
36
+ $ this ->relations = [];
33
37
}
34
38
35
- public function getPrimaryKeys (): array
39
+ public function getPrimaryKey (): array
36
40
{
37
- $ primaryKey = [];
38
-
39
- foreach ($ this ->schema ->getPrimaryKeys () as $ key ) {
40
- $ primaryKey [$ key ] = $ this ->values [$ key ];
41
+ if (empty ($ this ->primaryKey )) {
42
+ throw new \RuntimeException ('Cannot refer to the record via primary key, if it is not defined ' );
41
43
}
42
44
43
- return $ primaryKey ;
45
+ return $ this -> primaryKey ;
44
46
}
45
47
46
48
public function isNew (): bool
@@ -57,6 +59,17 @@ public function updateState(int $state): void
57
59
{
58
60
$ this ->state = $ state === self ::STATE_DELETE ? self ::STATE_DELETE : self ::STATE_UPDATE ;
59
61
$ this ->changed = [];
62
+
63
+ $ this ->updatePrimaryKey ();
64
+ }
65
+
66
+ private function updatePrimaryKey (): void
67
+ {
68
+ $ this ->primaryKey = [];
69
+
70
+ foreach ($ this ->schema ->getPrimaryKey () as $ key ) {
71
+ $ this ->primaryKey [$ key ] = $ this ->values [$ key ];
72
+ }
60
73
}
61
74
62
75
public function getSchema (): Schema
@@ -69,6 +82,11 @@ public function getModel(): Model
69
82
return $ this ->schema ->getModel ($ this );
70
83
}
71
84
85
+ public function isReferenceLoaded (string $ name ): bool
86
+ {
87
+ return isset ($ this ->relations [$ name ]);
88
+ }
89
+
72
90
/**
73
91
* @param string $name
74
92
* @return Record[]
@@ -84,44 +102,59 @@ public function getReference(string $name): array
84
102
85
103
public function fillReference (string $ name , array $ records ): void
86
104
{
87
- $ relation = $ this ->getSchema ()->getReference ($ name );
105
+ $ reference = $ this ->getSchema ()->getReference ($ name );
88
106
89
107
foreach ($ records as $ record ) {
90
- if (!$ this ->isRelated ($ relation , $ record )) {
108
+ if (!$ this ->isRelated ($ reference , $ record )) {
91
109
throw new \InvalidArgumentException ('The provided records are not related to this record ' );
92
110
}
93
111
}
94
112
95
- if (\count ($ records ) > 1 && $ relation ->isSingleRelationship ()) {
113
+ if (\count ($ records ) > 1 && $ reference ->isSingleRelationship ()) {
96
114
throw new \InvalidArgumentException ('The relationship cannot reference more than a single record ' );
97
115
}
98
116
99
117
$ this ->relations [$ name ] = array_values ($ records );
100
118
}
101
119
102
- public function isReferenceLoaded ( string $ name ): bool
120
+ private function isRelated ( Reference $ reference , Record $ record ): bool
103
121
{
104
- return isset ($ this ->relations [$ name ]);
105
- }
106
-
107
- private function isRelated (Reference $ relation , Record $ record ): bool
108
- {
109
- if ($ relation ->getReferencedSchema () !== $ record ->getSchema ()) {
122
+ if ($ reference ->getReferencedSchema () !== $ record ->getSchema ()) {
110
123
return false ;
111
124
}
112
125
113
- $ keys = $ relation ->getFields ();
114
- $ references = $ relation ->getReferencedFields ();
126
+ $ keys = $ reference ->getFields ();
127
+ $ fields = $ reference ->getReferencedFields ();
115
128
116
- while ($ keys ) {
117
- if (! $ relation -> matchValues ( $ this ->values [array_pop ( $ keys )], $ record ->values [array_pop ( $ references )]) ) {
129
+ foreach ($ keys as $ index => $ key ) {
130
+ if (( string ) $ this ->values [$ key ] !== ( string ) $ record ->values [$ fields [ $ index ]] ) {
118
131
return false ;
119
132
}
120
133
}
121
134
122
135
return true ;
123
136
}
124
137
138
+ public function getMappedRecords (): array
139
+ {
140
+ /** @var Record[] $records */
141
+ $ records = [spl_object_id ($ this ) => $ this ];
142
+
143
+ do {
144
+ foreach (current ($ records )->relations as $ relation ) {
145
+ foreach ($ relation as $ record ) {
146
+ $ id = spl_object_id ($ record );
147
+
148
+ if (!isset ($ records [$ id ])) {
149
+ $ records [$ id ] = $ record ;
150
+ }
151
+ }
152
+ }
153
+ } while (next ($ records ) !== false );
154
+
155
+ return array_values ($ records );
156
+ }
157
+
125
158
public function setDatabaseValues (array $ row )
126
159
{
127
160
if (array_keys ($ row ) !== array_keys ($ this ->values )) {
@@ -131,6 +164,7 @@ public function setDatabaseValues(array $row)
131
164
$ this ->values = $ row ;
132
165
$ this ->state = self ::STATE_UPDATE ;
133
166
$ this ->changed = [];
167
+ $ this ->updatePrimaryKey ();
134
168
}
135
169
136
170
public function getDatabaseValues (): array
@@ -163,10 +197,6 @@ public function offsetSet($offset, $value)
163
197
throw new \InvalidArgumentException ("Invalid record field ' $ offset' " );
164
198
}
165
199
166
- if ($ this ->state === self ::STATE_UPDATE && \in_array ($ offset , $ this ->schema ->getPrimaryKeys (), true )) {
167
- throw new \RuntimeException ('Cannot change values of primary keys for saved records ' );
168
- }
169
-
170
200
$ this ->values [$ offset ] = $ value ;
171
201
$ this ->changed [$ offset ] = true ;
172
202
}
0 commit comments