@@ -236,67 +236,72 @@ private function readRequest(
236236      return  array ($ e_value , $ errors , $ value , $ xaction );
237237    }
238238
239-     $ type  = $ option ->getType ();
240-     $ set_value  = null ;
241- 
242-     switch  ($ type ) {
243-       case  'int ' :
244-         if  (preg_match ('/^-?[0-9]+$/ ' , trim ($ value ))) {
245-           $ set_value  = (int )$ value ;
246-         } else  {
247-           $ e_value  = pht ('Invalid ' );
248-           $ errors [] = pht ('Value must be an integer. ' );
249-         }
250-         break ;
251-       case  'string ' :
252-       case  'enum ' :
253-         $ set_value  = (string )$ value ;
254-         break ;
255-       case  'list<string> ' :
256-         $ set_value  = $ request ->getStrList ('value ' );
257-         break ;
258-       case  'set ' :
259-         $ set_value  = array_fill_keys ($ request ->getStrList ('value ' ), true );
260-         break ;
261-       case  'bool ' :
262-         switch  ($ value ) {
263-           case  'true ' :
264-             $ set_value  = true ;
265-             break ;
266-           case  'false ' :
267-             $ set_value  = false ;
268-             break ;
269-           default :
239+     if  ($ option ->isCustomType ()) {
240+       $ info  = $ option ->getCustomObject ()->readRequest ($ option , $ request );
241+       list ($ e_value , $ errors , $ set_value , $ value ) = $ info ;
242+     } else  {
243+       $ type  = $ option ->getType ();
244+       $ set_value  = null ;
245+ 
246+       switch  ($ type ) {
247+         case  'int ' :
248+           if  (preg_match ('/^-?[0-9]+$/ ' , trim ($ value ))) {
249+             $ set_value  = (int )$ value ;
250+           } else  {
270251            $ e_value  = pht ('Invalid ' );
271-             $ errors [] = pht ('Value must be boolean, "true" or "false". ' );
272-             break ;
273-         }
274-         break ;
275-       case  'class ' :
276-         if  (!class_exists ($ value )) {
277-           $ e_value  = pht ('Invalid ' );
278-           $ errors [] = pht ('Class does not exist. ' );
279-         } else  {
280-           $ base  = $ option ->getBaseClass ();
281-           if  (!is_subclass_of ($ value , $ base )) {
252+             $ errors [] = pht ('Value must be an integer. ' );
253+           }
254+           break ;
255+         case  'string ' :
256+         case  'enum ' :
257+           $ set_value  = (string )$ value ;
258+           break ;
259+         case  'list<string> ' :
260+           $ set_value  = $ request ->getStrList ('value ' );
261+           break ;
262+         case  'set ' :
263+           $ set_value  = array_fill_keys ($ request ->getStrList ('value ' ), true );
264+           break ;
265+         case  'bool ' :
266+           switch  ($ value ) {
267+             case  'true ' :
268+               $ set_value  = true ;
269+               break ;
270+             case  'false ' :
271+               $ set_value  = false ;
272+               break ;
273+             default :
274+               $ e_value  = pht ('Invalid ' );
275+               $ errors [] = pht ('Value must be boolean, "true" or "false". ' );
276+               break ;
277+           }
278+           break ;
279+         case  'class ' :
280+           if  (!class_exists ($ value )) {
282281            $ e_value  = pht ('Invalid ' );
283-             $ errors [] = pht ('Class is  not of valid type . ' );
282+             $ errors [] = pht ('Class does  not exist . ' );
284283          } else  {
285-             $ set_value  = $ value ;
284+             $ base  = $ option ->getBaseClass ();
285+             if  (!is_subclass_of ($ value , $ base )) {
286+               $ e_value  = pht ('Invalid ' );
287+               $ errors [] = pht ('Class is not of valid type. ' );
288+             } else  {
289+               $ set_value  = $ value ;
290+             }
286291          }
287-         } 
288-         break ; 
289-       default : 
290-         $ json  =  json_decode ($ value,  true ); 
291-         if  ( $ json  ===  null  &&  strtolower ( $ value ) !=  ' null ' ) { 
292-           $ e_value   = pht (' Invalid ' ); 
293-           $ errors [] =  pht ( 
294-             ' The given value must be valid JSON. This means, among  ' . 
295-              ' other things, that you must wrap strings in double-quotes. ' ); 
296-         }  else  { 
297-           $ set_value  =  $ json ; 
298-         } 
299-          break ; 
292+            break ; 
293+         default : 
294+            $ json  =  json_decode ( $ value ,  true ); 
295+            if  ( $ json  ===  null  &&  strtolower ($ value) !=  ' null ' ) { 
296+              $ e_value  =  pht ( ' Invalid ' ); 
297+              $ errors []  = pht (
298+                ' The given value must be valid JSON. This means, among  ' . 
299+                ' other things, that you must wrap strings in double-quotes. ' ); 
300+           }  else  { 
301+              $ set_value  =  $ json ; 
302+           } 
303+            break ; 
304+       } 
300305    }
301306
302307    if  (!$ errors ) {
@@ -320,22 +325,26 @@ private function getDisplayValue(
320325      return  null ;
321326    }
322327
323-     $ type  = $ option ->getType ();
324-     $ value  = $ entry ->getValue ();
325-     switch  ($ type ) {
326-       case  'int ' :
327-       case  'string ' :
328-       case  'enum ' :
329-       case  'class ' :
330-         return  $ value ;
331-       case  'bool ' :
332-         return  $ value  ? 'true '  : 'false ' ;
333-       case  'list<string> ' :
334-         return  implode ("\n" , nonempty ($ value , array ()));
335-       case  'set ' :
336-         return  implode ("\n" , nonempty (array_keys ($ value ), array ()));
337-       default :
338-         return  PhabricatorConfigJSON::prettyPrintJSON ($ value );
328+     if  ($ option ->isCustomType ()) {
329+       return  $ option ->getCustomObject ()->getDisplayValue ($ option , $ entry );
330+     } else  {
331+       $ type  = $ option ->getType ();
332+       $ value  = $ entry ->getValue ();
333+       switch  ($ type ) {
334+         case  'int ' :
335+         case  'string ' :
336+         case  'enum ' :
337+         case  'class ' :
338+           return  $ value ;
339+         case  'bool ' :
340+           return  $ value  ? 'true '  : 'false ' ;
341+         case  'list<string> ' :
342+           return  implode ("\n" , nonempty ($ value , array ()));
343+         case  'set ' :
344+           return  implode ("\n" , nonempty (array_keys ($ value ), array ()));
345+         default :
346+           return  PhabricatorConfigJSON::prettyPrintJSON ($ value );
347+       }
339348    }
340349  }
341350
@@ -344,63 +353,70 @@ private function renderControl(
344353    $ display_value ,
345354    $ e_value ) {
346355
347-     $ type  = $ option ->getType ();
348-     switch  ($ type ) {
349-       case  'int ' :
350-       case  'string ' :
351-         $ control  = id (new  AphrontFormTextControl ());
352-         break ;
353-       case  'bool ' :
354-         $ control  = id (new  AphrontFormSelectControl ())
355-           ->setOptions (
356+     if  ($ option ->isCustomType ()) {
357+       $ control  = $ option ->getCustomObject ()->renderControl (
358+         $ option ,
359+         $ display_value ,
360+         $ e_value );
361+     } else  {
362+       $ type  = $ option ->getType ();
363+       switch  ($ type ) {
364+         case  'int ' :
365+         case  'string ' :
366+           $ control  = id (new  AphrontFormTextControl ());
367+           break ;
368+         case  'bool ' :
369+           $ control  = id (new  AphrontFormSelectControl ())
370+             ->setOptions (
371+               array (
372+                 ''       => pht ('(Use Default) ' ),
373+                 'true '   => idx ($ option ->getBoolOptions (), 0 ),
374+                 'false '  => idx ($ option ->getBoolOptions (), 1 ),
375+               ));
376+           break ;
377+         case  'enum ' :
378+           $ options  = array_mergev (
356379            array (
357-               ''       => pht ('(Use Default) ' ),
358-               'true '   => idx ($ option ->getBoolOptions (), 0 ),
359-               'false '  => idx ($ option ->getBoolOptions (), 1 ),
380+               array (''  => pht ('(Use Default) ' )),
381+               $ option ->getEnumOptions (),
360382            ));
361-         break ;
362-       case  'enum ' :
363-         $ options  = array_mergev (
364-           array (
365-             array (''  => pht ('(Use Default) ' )),
366-             $ option ->getEnumOptions (),
367-           ));
368-         $ control  = id (new  AphrontFormSelectControl ())
369-           ->setOptions ($ options );
370-         break ;
371-       case  'class ' :
372-         $ symbols  = id (new  PhutilSymbolLoader ())
373-           ->setType ('class ' )
374-           ->setAncestorClass ($ option ->getBaseClass ())
375-           ->setConcreteOnly (true )
376-           ->selectSymbolsWithoutLoading ();
377-         $ names  = ipull ($ symbols , 'name ' , 'name ' );
378-         asort ($ names );
379-         $ names  = array (
380-           ''  => pht ('(Use Default) ' ),
381-         ) + $ names ;
382- 
383-         $ control  = id (new  AphrontFormSelectControl ())
384-           ->setOptions ($ names );
385-         break ;
386-       case  'list<string> ' :
387-       case  'set ' :
388-         $ control  = id (new  AphrontFormTextAreaControl ())
389-           ->setCaption (pht ('Separate values with newlines or commas. ' ));
390-         break ;
391-       default :
392-         $ control  = id (new  AphrontFormTextAreaControl ())
393-           ->setHeight (AphrontFormTextAreaControl::HEIGHT_VERY_TALL )
394-           ->setCustomClass ('PhabricatorMonospaced ' )
395-           ->setCaption (pht ('Enter value in JSON. ' ));
396-         break ;
397-     }
383+           $ control  = id (new  AphrontFormSelectControl ())
384+             ->setOptions ($ options );
385+           break ;
386+         case  'class ' :
387+           $ symbols  = id (new  PhutilSymbolLoader ())
388+             ->setType ('class ' )
389+             ->setAncestorClass ($ option ->getBaseClass ())
390+             ->setConcreteOnly (true )
391+             ->selectSymbolsWithoutLoading ();
392+           $ names  = ipull ($ symbols , 'name ' , 'name ' );
393+           asort ($ names );
394+           $ names  = array (
395+             ''  => pht ('(Use Default) ' ),
396+           ) + $ names ;
397+ 
398+           $ control  = id (new  AphrontFormSelectControl ())
399+             ->setOptions ($ names );
400+           break ;
401+         case  'list<string> ' :
402+         case  'set ' :
403+           $ control  = id (new  AphrontFormTextAreaControl ())
404+             ->setCaption (pht ('Separate values with newlines or commas. ' ));
405+           break ;
406+         default :
407+           $ control  = id (new  AphrontFormTextAreaControl ())
408+             ->setHeight (AphrontFormTextAreaControl::HEIGHT_VERY_TALL )
409+             ->setCustomClass ('PhabricatorMonospaced ' )
410+             ->setCaption (pht ('Enter value in JSON. ' ));
411+           break ;
412+       }
398413
399-     $ control
400-       ->setLabel (pht ('Value ' ))
401-       ->setError ($ e_value )
402-       ->setValue ($ display_value )
403-       ->setName ('value ' );
414+       $ control
415+         ->setLabel (pht ('Value ' ))
416+         ->setError ($ e_value )
417+         ->setValue ($ display_value )
418+         ->setName ('value ' );
419+     }
404420
405421    if  ($ option ->getLocked ()) {
406422      $ control ->setDisabled (true );
0 commit comments