2016-02-03 5 views
5

का उपयोग करके बूलियन को झूठी अद्यतन कैसे करें मेरे पास एक बड़ी इकाई और एक बड़ा रूप है। मेरी इकाई को अपडेट करते समय, मैं केवल AJAX कॉल के माध्यम से, मेरे फॉर्म के कुछ हिस्सों को प्रस्तुत करता हूं। क्लाइंट साइड पर, मैं jquery और html5 फॉर्मडाटा का उपयोग कर रहा हूं, इसलिए मैं अपने फॉर्म में फ़ाइलों को भी भेज सकता हूं। यह सुनिश्चित करने के लिए कि जो फ़ील्ड प्रस्तुत नहीं किए गए हैं, वे प्रक्रिया में शून्य नहीं होंगे, मैं पैच विधि का उपयोग कर रहा हूं।Symfony3: पैच विधि

तो जब एक क्षेत्र मौजूद नहीं अनुरोध में है, यह छोड़ दिया के रूप में Symfony से है।

लेकिन जब क्षेत्र मैं अद्यतन एक बूलियन (एक एक चेकबॉक्स गाया) यह सच करने के लिए स्थापित किया गया था और मैं गलत पर यह स्थापित करना चाहते हैं, यह अनुरोध में पारित नहीं कर रहा है तो मेरे अद्यतन नजरअंदाज कर दिया है।

क्या अनुरोध में प्रकट होने के लिए अनचेक चेकबॉक्स को मजबूर करने का कोई आसान तरीका है?

संपादित
मैं this question पर अनुरोध में प्रदर्शित करने के अनियंत्रित चेक बॉक्स के लिए मजबूर करने के लिए एक रास्ता मिल गया, फेलिक्स Kling की टिप्पणी के लिए धन्यवाद:

$("input:checkbox:not(:checked)").each(function() { 
    formData.set($(this).attr('name'), formData.has($(this).attr('id')) ? '1' : '0'); 
}); 

दुर्भाग्य से, यह मेरी समस्या का समाधान नहीं किया, सिम्फनी के व्यवहार की वजह से:
- PUT का उपयोग करते समय, यदि बूलियन फ़ील्ड अनुरोध में प्रकट होता है, तो यह सत्य पर सेट हो जाता है, इसके मूल्य के बावजूद (भले ही यह "0" या "झूठा" हो)।
- पैच विधि का उपयोग करते समय, अनुरोध में दिखाई देने वाले फ़ील्ड को अनदेखा नहीं किया जाता है।

क्या डेटा ट्रांसफॉर्मर के साथ हल किया जा सकता है? (मैं इसे उपयोग नहीं किया है)

उत्तर

1

यहाँ है एक काम कर समाधान हो जाता है , में सुधार किया जा सकता है।

अनियंत्रित चेक बॉक्स अनुरोध में प्रदर्शित करने के this question पर फेलिक्स Kling की टिप्पणी के लिए धन्यवाद के लिए मजबूर करने के लिए, मैं जोड़ दिया है यह मेरा ajax अनुरोध से पहले JS:

$("input:checkbox:not(:checked)").each(function() { 
    formData.set($(this).attr('name'), formData.has($(this).attr('id')) ? '1' : '0'); 
}); 

फिर, Symfony पक्ष पर, मैं करने के लिए किया था BooleanToStringTransformer व्यवहार को ओवरराइड करें, जो true को स्ट्रिंग और false केवल शून्य मान के लिए देता है। पिछली पंक्ति में बदलाव करना, अब हम झूठी लौटाते हैं यदि मान सत्य (डिफ़ॉल्ट रूप से "1") के लिए परिभाषित मान से मेल नहीं खाता है। इसलिए यदि फॉर्म द्वारा लौटाया गया मान "0" है, तो हमें झूठी मिलती है, जैसा कि अपेक्षित है।

public function reverseTransform($value) 
{ 
    if (null === $value) { 
     return false; 
    } 

    if (!is_string($value)) { 
     throw new TransformationFailedException('Expected a string.'); 
    } 

    return ($this->trueValue === $value); // initially: "return true;" 
} 

the docs के बाद, मैं अपने खुद के DataTransformer है, साथ ही एक कस्टम AjaxCheckboxType

दुर्भाग्य से बनाया है, ऐसा लगता है कि Symfony दोनों DataTransformers (मेरा और मूल एक), एक के बाद एक का उपयोग करता है अन्य, तो यह काम नहीं किया। दस्तावेज़ों में वे TextTypeCheckboxType नहीं बढ़ाते हैं, जो मुझे मिली समस्याओं की व्याख्या करनी चाहिए।

मैंने अपने स्वयं के अजाक्स चेकबॉक्स टाइप में पूरे CheckboxType class को कॉपी और पेस्ट करना समाप्त कर दिया, केवल मेरा उपयोग करने के लिए डेटा ट्रांसफॉर्मर के कॉल को बदल दिया।

डेटाट्रांसफॉर्मर को पूरी तरह से ओवरराइड करने के लिए एक बहुत अच्छा समाधान होगा, लेकिन मुझे नहीं पता कि कैसे।

+1

आप डेटा ट्रांसफॉर्मर को $ builder-> resetViewTransformers() के साथ रीसेट कर सकते हैं। फिर अपना खुद का डेटा ट्रांसफॉर्मर जोड़ें। – Falc

+0

@Falc उत्कृष्ट! वास्तव में मुझे क्या चाहिए! – Roubi

+0

अच्छा समाधान! मैंने इस 'व्यवहार को' accept_null_on_patch' फ़ॉर्म फ़ील्ड विकल्प के माध्यम से आसानी से कॉन्फ़िगर करने योग्य बनाने के लिए 'चेकबॉक्स टाइप' को विस्तारित करने के लिए 'पैच करने योग्य चेकबॉक्स टाइप प्रकार' के भीतर कार्यान्वित किया। यदि यह सत्य पर सेट किया गया है, तो यह सभी व्यूट्रांसफॉर्मर्स को हटा देता है और इसके बजाय 'पैचेबल चेकबॉक्सबोलियन टॉस्ट्रिंग ट्रान्सफॉर्मर' जोड़ता है। – spackmat

4

आप बिल्कुल सही कह रहे हैं, Symfony यह ध्यान नहीं देगा, तो विधि this line in Request Handler की वजह से PATCH है:

$form->submit($data, 'PATCH' !== $method); 

अब, मैं आम तौर पर सुझाव है कि आप एक PUT अनुरोध है कि यदि का उपयोग एक विकल्प है, लेकिन यदि यह नहीं है तो FormInterface::submit($submittedData, $clearMissing = true) पर दूसरा तर्क है जो आप के बाद हैं।

"उचित" जिस तरह से शायद Symfony\Component\Form\RequestHandlerInterface का अपना स्वयं का कार्यान्वयन जो $clearMissingtrue होने के लिए मजबूर होना पड़ा बनाने के लिए किया जाएगा।

अन्य, रास्ता बहुत आसान है लेकिन सभी उपयोग-मामलों के लिए काम नहीं कर सकता है: सीधे $form->submit() का उपयोग करें।

आप निम्नलिखित कोड है, तो:

$form->handleRequest($request); 

आप कर सकते हैं:

$form->submit($request->get($form->getName()), true); 

तुम भी दूसरा पैरामीटर छोड़ सकते हैं के बाद से true डिफ़ॉल्ट मान

+0

आपके उत्तर के लिए धन्यवाद। मैं अपने सभी क्षेत्रों के लिए पैच के व्यवहार को वापस नहीं कर सकता। चूंकि मैं फॉर्म का केवल एक छोटा सा हिस्सा प्रस्तुत कर रहा हूं, इसलिए * मैंने * अनुपलब्ध फ़ील्ड को अद्यतन पर छूने के लिए छोड़ दिया है ... मैंने जो चेकबॉक्स प्रस्तुत किए हैं, उन्हें छोड़कर। मुझे लगता है कि मुझे चेकबॉक्स को इस तरह से प्रस्तुत करने की आवश्यकता है कि वे जमा अनुरोध में तब भी दिखाई देंगे जब वे * चेक नहीं किए गए हों *। – Roubi

1

Symfony बॉक्स से बाहर इस संभालती है, बस अपने पैच-पेलोड तैयार ठीक से :)

Symfony CheckboxType, कम से कम वर्तमान संस्करण में 3.3 (2.3 के बाद से की तरह लगता है, नीचे अद्यतन देखें), एक इनपुट स्वीकार करता है null का मान, जिसे "चेक नहीं किया गया" के रूप में व्याख्या किया गया है (जैसा कि आप Roubi's really helpful answer में स्निपेट के लाइन 3-5 में देख सकते हैं)।

तो अपने क्लाइंट साइड AJAX-PATCH नियंत्रक में आप null करने के लिए अपने application/merge-patch+json पेलोड में अपने (गंदा) अनियंत्रित चेकबॉक्स क्षेत्र की का मान सेट और सब कुछ ठीक है। कोई फॉर्म एक्सटेंशन ओवरराइटिंग चेकबॉक्स टाइप का व्यवहार बिल्कुल जरूरी नहीं है।

समस्या यह है: मुझे लगता है कि आप HTTP-POST-payload के मानों को null पर सेट नहीं कर सकते हैं, इसलिए यह केवल अनुरोध निकाय के भीतर JSON (या अन्य संगत) पेलोड के साथ काम करता है।

एक साधारण डेमो

इस प्रदर्शन करने के लिए, तो आप इस सरलीकृत परीक्षण नियंत्रक का उपयोग कर सकते हैं:

/** 
* @Route("/test/patch.json", name="test_patch") 
* @Method({"PATCH"}) 
*/ 
public function patchAction(\Symfony\Component\HttpFoundation\Request $request) 
{ 
    $form = $this->createFormBuilder(['checkbox' => true, 'dummyfield' => 'presetvalue'], ['csrf_protection' => false]) 
     ->setAction($this->generateUrl($request->get('_route'))) 
     ->setMethod('PATCH') 
     ->add('checkbox', \Symfony\Component\Form\Extension\Core\Type\CheckboxType::class) 
     ->add('dummyfield', \Symfony\Component\Form\Extension\Core\Type\TextType::class) 
     ->getForm() 
    ; 
    $form->submit(json_decode($request->getContent(), true), false); 

    return new \Symfony\Component\HttpFoundation\JsonResponse($form->getData()); 
} 

Content-Type: application/merge-patch+json साथ या इस मामले को भी किसी भी मान्य JSON-पेलोड, निम्नलिखित वसीयत में PATCH-अनुरोधों के लिए होती हैं:

null मूल्य के साथ चेकबॉक्स को जमा

{"checkbox": null} 

गलत पर चेकबॉक्स के ऊपर लिख देगा:

{"checkbox": false, "dummyfield": "presetvalue"} 

और अपने मूल मूल्य के साथ चेकबॉक्स प्रस्तुत करने

{"checkbox": "1"} 

सच करने के लिए चेकबॉक्स सेट हो जाएगा (यह भी पहले सच था)

{"checkbox": true, "dummyfield": "presetvalue"} 

और चेकबॉक्स

के लिए कोई सबमिट मूल्य नहीं

अपनी प्रारंभिक सच राज्य में चेकबॉक्स छोड़ देंगे और केवल dummyfield अधिलेखित कर देता है:

{"checkbox": true, "dummyfield": "requestvalue"} 

यह कैसे एक पैच अनुरोध काम करना चाहिए, बिना किसी अतिरिक्त जरूरत छिपा आदानों है। बस अपने JSON-payload को क्लाइंट-साइड पर ठीक से तैयार करें और आप ठीक हैं।

ठीक है, लेकिन विस्तारित चॉइसटाइप/EntityType के बारे में क्या?

विस्तारित चॉइसटाइप (या इसके प्रकार के बच्चे प्रकार एंटिटीटाइप) के लिए, जो चेकबॉक्स या रेडियोबुटन प्रस्तुत करता है और सबमिट किए गए पेलोड के भीतर चेक किए गए चेकबॉक्स/रेडियोबुटन मानों की एक साधारण सूची की अपेक्षा करता है, यह सरल समाधान काम नहीं करता है। मैंने एक फॉर्म एक्सटेंशन लागू किया, जिसमें उन फ़ील्ड पर PRE_SUBMIT के लिए इवेंट श्रोता जोड़ा गया, गैर सबमिट किए गए चेकबॉक्स/रेडियोबुटन को शून्य पर सेट किया गया। चेकबॉक्स टाइप के बंद-श्रोता के बाद इस ईवेंट श्रोता को कॉल किया जाना चाहिए, सरल सूची ["1", "3"] को हैश में चेकबॉक्स-मानों के साथ कुंजी और मान के रूप में स्थानांतरित करना। -1 की प्राथमिकता मेरे लिए काम करती है। इसलिए ["1" => "1", "3" => "3"] बंद होने से बाहर आने से मेरे श्रोता के बाद ["1" => "1", "2" => null, "3" => "3"] हो जाता है। मेरी PatchableChoiceTypeExtension के श्रोता इस तरह मूल रूप से दिखता है:

$builder->addEventListener(
    \Symfony\Component\Form\FormEvents::PRE_SUBMIT, 
    function (\Symfony\Component\Form\FormEvent $event) { 
     if ('PATCH' === $event->getForm()->getRoot()->getConfig()->getMethod() 
      && $event->getForm()->getConfig()->getOption('expanded', false) 
     ) { 
      $data = $event->getData(); 
      foreach ($event->getForm()->all() as $type) { 
       if (!array_key_exists($type->getName(), $data)) { 
        $data[$type->getName()] = null; 
       } 
      } 
      ksort($data); 
      $event->setData($data); 
     } 
    }, -1 
); 

अद्यतन: /Symfony/Component/Form/Form.php (यह Symfony 2.3 के बाद से वहाँ है) में प्रस्तुत-विधि के भीतर इस टिप्पणी पर एक नजर है:

// Treat false as NULL to support binding false to checkboxes. 
// Don't convert NULL to a string here in order to determine later 
// whether an empty value has been submitted or whether no value has 
// been submitted at all. This is important for processing checkboxes 
// and radio buttons with empty values. 

अद्यतन 2017/09/12: Radiogroups Checkboxgroups के रूप में एक ही तरह से नियंत्रित किया जाना चाहिए, इसलिए मेरे श्रोता दोनों संभालती है। चयन और बहु ​​चयन बॉक्स के ठीक से काम करते हैं।

संबंधित मुद्दे