@@ -40,18 +40,30 @@ class DirectForeignKeyMethodDescriptor implements MethodDescriptorInterface
40
40
* @var AnnotationParser
41
41
*/
42
42
private $ annotationParser ;
43
+ /**
44
+ * @var string
45
+ */
46
+ private $ beanNamespace ;
43
47
44
48
/**
45
49
* @param ForeignKeyConstraint $fk The foreign key pointing to our bean
46
50
* @param Table $mainTable The main table that is pointed to
47
51
* @param NamingStrategyInterface $namingStrategy
52
+ * @param AnnotationParser $annotationParser
53
+ * @param string $beanNamespace
48
54
*/
49
- public function __construct (ForeignKeyConstraint $ fk , Table $ mainTable , NamingStrategyInterface $ namingStrategy , AnnotationParser $ annotationParser )
50
- {
55
+ public function __construct (
56
+ ForeignKeyConstraint $ fk ,
57
+ Table $ mainTable ,
58
+ NamingStrategyInterface $ namingStrategy ,
59
+ AnnotationParser $ annotationParser ,
60
+ string $ beanNamespace
61
+ ) {
51
62
$ this ->foreignKey = $ fk ;
52
63
$ this ->mainTable = $ mainTable ;
53
64
$ this ->namingStrategy = $ namingStrategy ;
54
65
$ this ->annotationParser = $ annotationParser ;
66
+ $ this ->beanNamespace = $ beanNamespace ;
55
67
}
56
68
57
69
/**
@@ -100,23 +112,37 @@ public function useAlternativeName(): void
100
112
public function getCode () : array
101
113
{
102
114
$ beanClass = $ this ->getBeanClassName ();
115
+ $ tdbmFk = ForeignKey::createFromFk ($ this ->foreignKey );
103
116
104
117
$ getter = new MethodGenerator ($ this ->getName ());
105
- $ getter ->setDocBlock (sprintf ('Returns the list of %s pointing to this bean via the %s column. ' , $ beanClass , implode (', ' , $ this ->foreignKey ->getUnquotedLocalColumns ())));
106
- $ getter ->getDocBlock ()->setTag (new ReturnTag ([
107
- $ beanClass .'[] ' ,
108
- '\\' .AlterableResultIterator::class
109
- ]));
110
- $ getter ->setReturnType (AlterableResultIterator::class);
111
118
112
- $ tdbmFk = ForeignKey::createFromFk ($ this ->foreignKey );
119
+ if ($ this ->hasLocalUniqueIndex ()) {
120
+ $ getter ->setDocBlock (sprintf ('Returns the %s pointing to this bean via the %s column. ' , $ beanClass , implode (', ' , $ this ->foreignKey ->getUnquotedLocalColumns ())));
121
+ $ classType = '\\' . $ this ->beanNamespace . '\\' . $ beanClass ;
122
+ $ getter ->getDocBlock ()->setTag (new ReturnTag ([$ classType . '|null ' ]));
123
+ $ getter ->setReturnType ('? ' . $ classType );
113
124
114
- $ code = sprintf (
115
- 'return $this->retrieveManyToOneRelationshipsStorage(%s, %s, %s); ' ,
116
- var_export ($ this ->foreignKey ->getLocalTableName (), true ),
117
- var_export ($ tdbmFk ->getCacheKey (), true ),
118
- $ this ->getFilters ($ this ->foreignKey )
119
- );
125
+ $ code = sprintf (
126
+ 'return $this->retrieveManyToOneRelationshipsStorage(%s, %s, %s)->first(); ' ,
127
+ var_export ($ this ->foreignKey ->getLocalTableName (), true ),
128
+ var_export ($ tdbmFk ->getCacheKey (), true ),
129
+ $ this ->getFilters ($ this ->foreignKey )
130
+ );
131
+ } else {
132
+ $ getter ->setDocBlock (sprintf ('Returns the list of %s pointing to this bean via the %s column. ' , $ beanClass , implode (', ' , $ this ->foreignKey ->getUnquotedLocalColumns ())));
133
+ $ getter ->getDocBlock ()->setTag (new ReturnTag ([
134
+ $ beanClass . '[] ' ,
135
+ '\\' . AlterableResultIterator::class
136
+ ]));
137
+ $ getter ->setReturnType (AlterableResultIterator::class);
138
+
139
+ $ code = sprintf (
140
+ 'return $this->retrieveManyToOneRelationshipsStorage(%s, %s, %s); ' ,
141
+ var_export ($ this ->foreignKey ->getLocalTableName (), true ),
142
+ var_export ($ tdbmFk ->getCacheKey (), true ),
143
+ $ this ->getFilters ($ this ->foreignKey )
144
+ );
145
+ }
120
146
121
147
$ getter ->setBody ($ code );
122
148
@@ -144,6 +170,25 @@ private function getFilters(ForeignKeyConstraint $fk) : string
144
170
return $ parametersCode ;
145
171
}
146
172
173
+ /**
174
+ * Check if the ForeignKey have an unique index
175
+ *
176
+ * @return bool
177
+ */
178
+ private function hasLocalUniqueIndex (): bool
179
+ {
180
+ foreach ($ this ->getForeignKey ()->getLocalTable ()->getIndexes () as $ index ) {
181
+ if (
182
+ $ index ->isUnique ()
183
+ && count ($ index ->getUnquotedColumns ()) === count ($ this ->getForeignKey ()->getUnquotedLocalColumns ())
184
+ && !array_diff ($ index ->getUnquotedColumns (), $ this ->getForeignKey ()->getUnquotedLocalColumns ()) // Check for permuted columns too
185
+ ) {
186
+ return true ;
187
+ }
188
+ }
189
+ return false ;
190
+ }
191
+
147
192
/**
148
193
* Returns an array of classes that needs a "use" for this method.
149
194
*
@@ -181,17 +226,21 @@ public function getJsonSerializeCode() : string
181
226
$ class = $ this ->getBeanClassName ();
182
227
$ variableName = '$ ' . TDBMDaoGenerator::toVariableName ($ class );
183
228
$ getter = $ this ->getName ();
184
- $ code = <<<PHP
229
+ if ($ this ->hasLocalUniqueIndex ()) {
230
+ $ code = "\$array[' $ index'] = ( \$object = \$this-> $ getter()) ? \$object-> $ format : null; " ;
231
+ } else {
232
+ $ code = <<<PHP
185
233
\$array[' $ index'] = array_map(function ( $ class $ variableName) {
186
234
return $ {variableName}-> $ format;
187
235
}, \$this-> $ getter()->toArray());
188
236
PHP ;
237
+ }
189
238
if (!$ isIncluded ) {
190
239
$ code = preg_replace ('(\n) ' , '\0 ' , $ code );
191
240
$ code = <<<PHP
192
241
if (! \$stopRecursion) {
193
242
$ code
194
- };
243
+ }
195
244
PHP ;
196
245
}
197
246
return $ code ;
0 commit comments