2929 */
3030final class FilterTypeFactory extends AbstractTypeFactory
3131{
32+ /**
33+ * @var Filter[][]
34+ */
35+ private $ customOperators ;
36+
3237 /**
3338 * Create an InputObjectType from a Doctrine entity
3439 *
@@ -166,37 +171,45 @@ private function getConditionFieldsType(string $className, string $typeName): In
166171 'name ' => $ typeName . 'ConditionFields ' ,
167172 'description ' => 'Type to specify conditions on fields ' ,
168173 'fields ' => function () use ($ className , $ typeName ) {
169- $ standardFilters = [];
174+ $ filters = [];
170175 $ metadata = $ this ->entityManager ->getClassMetadata ($ className );
171176
172- // Get all entity scalar fields
177+ // Get custom operators
178+ $ this ->customOperators = [];
179+ $ this ->readCustomOperatorsFromAnnotation ($ metadata ->reflClass );
180+
181+ // Get all scalar fields
173182 foreach ($ metadata ->fieldMappings as $ mapping ) {
174183 /** @var LeafType $leafType */
175184 $ leafType = $ this ->types ->get ($ mapping ['type ' ]);
176185 $ fieldName = $ mapping ['fieldName ' ];
186+ $ operators = $ this ->getOperators ($ fieldName , $ leafType , false );
177187
178- $ field = [
179- 'name ' => $ fieldName ,
180- 'type ' => $ this ->getFieldType ($ typeName , $ fieldName , $ leafType , false ),
181- ];
182- $ standardFilters [] = $ field ;
188+ $ filters [] = $ this ->getFieldConfiguration ($ typeName , $ fieldName , $ operators );
183189 }
184190
185- // Get all entity collection fields
191+ // Get all collection fields
186192 foreach ($ metadata ->associationMappings as $ mapping ) {
187193 $ fieldName = $ mapping ['fieldName ' ];
194+ $ operators = $ this ->getOperators ($ fieldName , Type::id (), $ metadata ->isCollectionValuedAssociation ($ fieldName ));
188195
189- $ field = [
190- 'name ' => $ fieldName ,
191- 'type ' => $ this ->getFieldType ($ typeName , $ fieldName , Type::id (), $ metadata ->isCollectionValuedAssociation ($ fieldName )),
192- ];
193- $ standardFilters [] = $ field ;
196+ $ filters [] = $ this ->getFieldConfiguration ($ typeName , $ fieldName , $ operators );
194197 }
195198
196- // Get custom fields
197- $ customFilters = $ this ->getCustomFiltersFromAnnotation ($ metadata ->reflClass );
199+ // Get all custom fields defined by custom operators
200+ foreach ($ this ->customOperators as $ fieldName => $ customOperators ) {
201+ $ operators = [];
202+ /** @var Filter $customOperator */
203+ foreach ($ customOperators as $ customOperator ) {
204+ /** @var LeafType $leafType */
205+ $ leafType = $ this ->types ->get ($ customOperator ->type );
206+ $ operators [$ customOperator ->operator ] = $ leafType ;
207+ }
208+
209+ $ filters [] = $ this ->getFieldConfiguration ($ typeName , $ fieldName , $ operators );
210+ }
198211
199- return array_merge ( $ standardFilters , $ customFilters ) ;
212+ return $ filters ;
200213 },
201214 ]);
202215
@@ -206,16 +219,72 @@ private function getConditionFieldsType(string $className, string $typeName): In
206219 }
207220
208221 /**
209- * Get the custom filters declared on the class via annotations
222+ * Get configuration for field
210223 *
211- * @param ReflectionClass $class
224+ * @param string $typeName
225+ * @param string $fieldName
226+ * @param LeafType[] $operators
212227 *
213228 * @return array
214229 */
215- private function getCustomFiltersFromAnnotation ( ReflectionClass $ class ): array
230+ private function getFieldConfiguration ( string $ typeName , string $ fieldName , array $ operators ): array
216231 {
217- $ result = [];
232+ return [
233+ 'name ' => $ fieldName ,
234+ 'type ' => $ this ->getFieldType ($ typeName , $ fieldName , $ operators ),
235+ ];
236+ }
218237
238+ /**
239+ * Return a map of operator class name and their leaf type, including custom operator for the given fieldName
240+ *
241+ * @param string $fieldName
242+ * @param LeafType $leafType
243+ * @param bool $isCollection
244+ *
245+ * @return LeafType[] indexed by operator class name
246+ */
247+ private function getOperators (string $ fieldName , LeafType $ leafType , bool $ isCollection ): array
248+ {
249+ if ($ isCollection ) {
250+ $ operators = [
251+ ContainOperatorType::class => $ leafType ,
252+ EmptyOperatorType::class => $ leafType ,
253+ ];
254+ } else {
255+ $ operators = [
256+ BetweenOperatorType::class => $ leafType ,
257+ EqualOperatorType::class => $ leafType ,
258+ GreaterOperatorType::class => $ leafType ,
259+ GreaterOrEqualOperatorType::class => $ leafType ,
260+ InOperatorType::class => $ leafType ,
261+ LessOperatorType::class => $ leafType ,
262+ LessOrEqualOperatorType::class => $ leafType ,
263+ LikeOperatorType::class => $ leafType ,
264+ NullOperatorType::class => $ leafType ,
265+ ];
266+ }
267+
268+ // Add custom filters if any
269+ if (isset ($ this ->customOperators [$ fieldName ])) {
270+ foreach ($ this ->customOperators [$ fieldName ] as $ filter ) {
271+ $ leafType = $ this ->types ->get ($ filter ->type );
272+ $ operators [$ filter ->operator ] = $ leafType ;
273+ }
274+
275+ unset($ this ->customOperators [$ fieldName ]);
276+ }
277+
278+ return $ operators ;
279+ }
280+
281+ /**
282+ * Get the custom operators declared on the class via annotations indexed by their field name
283+ *
284+ * @param ReflectionClass $class
285+ */
286+ private function readCustomOperatorsFromAnnotation (ReflectionClass $ class ): void
287+ {
219288 $ filters = $ this ->getAnnotationReader ()->getClassAnnotation ($ class , Filters::class);
220289 if ($ filters ) {
221290
@@ -224,40 +293,33 @@ private function getCustomFiltersFromAnnotation(ReflectionClass $class): array
224293 $ className = $ filter ->operator ;
225294 $ this ->throwIfInvalidAnnotation ($ class , 'Filter ' , AbstractOperator::class, $ className );
226295
227- /** @var LeafType $leafType */
228- $ leafType = $ this ->types ->get ($ filter ->type );
229- $ instance = $ this ->types ->getOperator ($ className , $ leafType );
230-
231- $ result [] = [
232- 'name ' => $ filter ->field ,
233- 'type ' => $ instance ,
234- ];
296+ if (!isset ($ this ->customOperators [$ filter ->field ])) {
297+ $ this ->customOperators [$ filter ->field ] = [];
298+ }
299+ $ this ->customOperators [$ filter ->field ][] = $ filter ;
235300 }
236301 }
237302
238303 if ($ class ->getParentClass ()) {
239- return array_merge ( $ result , $ this ->getCustomFiltersFromAnnotation ($ class ->getParentClass () ));
304+ $ this ->readCustomOperatorsFromAnnotation ($ class ->getParentClass ());
240305 }
241-
242- return $ result ;
243306 }
244307
245308 /**
246309 * Get the type for a specific field
247310 *
248311 * @param string $typeName
249312 * @param string $fieldName
250- * @param LeafType $leafType
251- * @param bool $isCollection
313+ * @param LeafType[] $operators
252314 *
253315 * @return InputObjectType
254316 */
255- private function getFieldType (string $ typeName , string $ fieldName , LeafType $ leafType , bool $ isCollection ): InputObjectType
317+ private function getFieldType (string $ typeName , string $ fieldName , array $ operators ): InputObjectType
256318 {
257319 $ fieldType = new InputObjectType ([
258320 'name ' => $ typeName . 'ConditionField ' . ucfirst ($ fieldName ),
259321 'description ' => 'Type to specify a condition on a specific field ' ,
260- 'fields ' => $ this ->getOperators ( $ leafType , $ isCollection ),
322+ 'fields ' => $ this ->getOperatorConfiguration ( $ operators ),
261323 ]);
262324
263325 $ this ->types ->registerInstance ($ fieldType );
@@ -266,36 +328,16 @@ private function getFieldType(string $typeName, string $fieldName, LeafType $lea
266328 }
267329
268330 /**
269- * Get standard operators for a specific leaf type
331+ * Get operators configuration for a specific leaf type
270332 *
271- * @param LeafType $leafType
272- * @param bool $isCollection
333+ * @param LeafType[] $operators
273334 *
274335 * @return array
275336 */
276- private function getOperators ( LeafType $ leafType , bool $ isCollection ): array
337+ private function getOperatorConfiguration ( array $ operators ): array
277338 {
278- if ($ isCollection ) {
279- $ operators = [
280- ContainOperatorType::class,
281- EmptyOperatorType::class,
282- ];
283- } else {
284- $ operators = [
285- BetweenOperatorType::class,
286- EqualOperatorType::class,
287- GreaterOperatorType::class,
288- GreaterOrEqualOperatorType::class,
289- InOperatorType::class,
290- LessOperatorType::class,
291- LessOrEqualOperatorType::class,
292- LikeOperatorType::class,
293- NullOperatorType::class,
294- ];
295- }
296339 $ conf = [];
297-
298- foreach ($ operators as $ operator ) {
340+ foreach ($ operators as $ operator => $ leafType ) {
299341 $ instance = $ this ->types ->getOperator ($ operator , $ leafType );
300342 $ field = [
301343 'name ' => $ this ->getOperatorFieldName ($ operator ),
0 commit comments