2011-09-25 10 views
10

के अंदर मैं इस पर नया हूं, सजावट राजशाही झुकाव, लेकिन मेरे पास दो महत्वपूर्ण प्रश्न हैं जिन्हें मैं अपने सिर को नहीं ले सकता। प्रश्न एक कुछ उदाहरणZend_Framework सजावटी लपेटें लेबल और व्यूहेल्पर एक div

$decorate = array(
    array('ViewHelper'), 
    array('Description'), 
    array('Errors', array('class'=>'error')), 
    array('Label', array('tag'=>'div', 'separator'=>' ')), 
    array('HtmlTag', array('tag' => 'li', 'class'=>'element')), 
); 

... 

$name = new Zend_Form_Element_Text('title'); 
$name->setLabel('Title') 
    ->setDescription("No --- way"); 

$name->setDecorator($decorate); 

आउटपुट कौन सा

<li class="element"> 
    <label for="title" class="required">Title</label> 
    <input type="text" name="title" id="title" value=""> 
    <p class="hint">No --- way</p> 
    <ul class="error"> 
     <li>Value is required and can't be empty</li> 
    </ul> 
</li> 

प्रश्न # 1

कैसे मैं label और एक div टैग के आसपास input लपेट है द्वारा पीछा किया जाता? तो उत्पादन इस प्रकार है:

<li class="element"> 
    <div> 
     <label for="title" class="required">Title</label> 
     <input type="text" name="title" id="title" value=""> 
    </div> 
    <p class="hint">No --- way</p> 
    <ul class="error"> 
     <li>Value is required and can't be empty</li> 
    </ul> 
</li> 

प्रश्न # 2

$decorate सरणी में elements के आदेश के साथ क्या चल रहा है? वे कोई संवेदना नहीं बनाते हैं!

उत्तर

21

decorator pattern मौजूदा कक्षाओं में मौजूदा वर्गों को बदलने के बिना कार्यक्षमता जोड़ने के लिए एक डिज़ाइन पैटर्न है। इसके अलावा, एक सजावटी वर्ग खुद को किसी अन्य वर्ग के चारों ओर लपेटता है, और आमतौर पर सजाए गए वर्ग के समान इंटरफेस का खुलासा करता है।

बुनियादी उदाहरण:

interface Renderable 
{ 
    public function render(); 
} 

class HelloWorld 
    implements Renderable 
{ 
    public function render() 
    { 
     return 'Hello world!'; 
    } 
} 

class BoldDecorator 
    implements Renderable 
{ 
    protected $_decoratee; 

    public function __construct(Renderable $decoratee) 
    { 
     $this->_decoratee = $decoratee; 
    } 

    public function render() 
    { 
     return '<b>' . $this->_decoratee->render() . '</b>'; 
    } 
} 

// wrapping (decorating) HelloWorld in a BoldDecorator 
$decorator = new BoldDecorator(new HelloWorld()); 
echo $decorator->render(); 

// will output 
<b>Hello world!</b> 

अब, आप को लगता है कि क्योंकि Zend_Form_Decorator_* कक्षाएं सज्जाकार हैं, और एक render विधि है, यह स्वचालित रूप से render विधि सजाया वर्ग के 'उत्पादन होगा हमेशा मतलब है परीक्षा हो सकती है सजावटी द्वारा अतिरिक्त सामग्री के साथ लपेटा जाना चाहिए।

class DivDecorator 
    implements Renderable 
{ 
    const PREPEND = 'prepend'; 
    const APPEND = 'append'; 
    const WRAP = 'wrap'; 

    protected $_placement; 

    protected $_decoratee; 

    public function __construct(Renderable $decoratee, $placement = self::WRAP) 
    { 
     $this->_decoratee = $decoratee; 
     $this->_placement = $placement; 
    } 

    public function render() 
    { 
     $content = $this->_decoratee->render(); 
     switch($this->_placement) 
     { 
      case self::PREPEND: 
       $content = '<div></div>' . $content; 
       break; 
      case self::APPEND: 
       $content = $content . '<div></div>'; 
       break; 
      case self::WRAP: 
      default: 
       $content = '<div>' . $content . '</div>'; 
     } 

     return $content; 
    } 
} 

// wrapping (decorating) HelloWorld in a BoldDecorator and a DivDecorator (with DivDecorator::APPEND) 
$decorator = new DivDecorator(new BoldDecorator(new HelloWorld()), DivDecorator::APPEND); 
echo $decorator->render(); 

// will output 
<b>Hello world!</b><div></div> 

इस में है: लेकिन इसके बाद के संस्करण हमारी बुनियादी उदाहरण के निरीक्षण पर, हम आसानी से यह अनिवार्य रूप से, के रूप में इस अतिरिक्त (यद्यपि काफी बेकार) उदाहरण के रूप में रेखांकित पाठ्यक्रम के सभी पर मामला हो की जरूरत नहीं है देख सकते हैं तथ्य यह है कि Zend_Form_Decorator_* सजावटी कितने काम करते हैं, अगर उनके लिए यह प्लेसमेंट कार्यक्षमता हो।

सजावट करने वालों के लिए जहां यह समझ में आता है, उदाहरण के लिए, आप setOption('placement', 'append') के साथ प्लेसमेंट को नियंत्रित कर सकते हैं, या विकल्पों के लिए 'placement' => 'append' विकल्प को पास करके।

Zend_Form_Decorator_PrepareElements के लिए, उदाहरण के लिए, इस नियुक्ति के विकल्प बेकार है और वजह, नजरअंदाज कर दिया के रूप में यह तैयार प्रपत्र तत्व एक ViewScript डेकोरेटर द्वारा प्रयोग की जाने, यह सज्जाकार कि सजाया तत्व की प्रदान की गई सामग्री स्पर्श नहीं करता है में से एक बना ।

व्यक्तिगत सज्जाकार के डिफ़ॉल्ट कार्यक्षमता के आधार पर, या तो सजाया वर्ग की सामग्री, लिपटे संलग्न, prepended है, त्याग या कुछ पूरी तरह से अलग सजाया वर्ग के लिए किया जाता है, सीधे सामग्री के लिए कुछ जोड़े बिना, अगले सजावट करने के लिए सामग्री के साथ गुजरने से पहले। इस सरल उदाहरण पर विचार करें:

class ErrorClassDecorator 
    implements Renderable 
{ 
    protected $_decoratee; 

    public function __construct(Renderable $decoratee) 
    { 
     $this->_decoratee = $decoratee; 
    } 

    public function render() 
    { 
     // imagine the following two fictional methods 
     if($this->_decoratee->hasErrors()) 
     { 
      $this->_decoratee->setAttribute('class', 'errors'); 
     } 

     // we didn't touch the rendered content, we just set the css class to 'errors' above 
     return $this->_decoratee->render(); 
    } 
} 

// wrapping (decorating) HelloWorld in a BoldDecorator and an ErrorClassDecorator 
$decorator = new ErrorClassDecorator(new BoldDecorator(new HelloWorld())); 
echo $decorator->render(); 

// might output something like 
<b class="errors">Hello world!</b> 

अब, जब आप एक Zend_Form_Element_* तत्व के लिए सज्जाकार निर्धारित करते हैं, वे लिपटे हो जाएगा, और फलस्वरूप, जिसमें वे जोड़ रहे हैं क्रम में, मार डाला।तो, अपने उदाहरण को देखते हुए:

$decorate = array(
    array('ViewHelper'), 
    array('Description'), 
    array('Errors', array('class'=>'error')), 
    array('Label', array('tag'=>'div', 'separator'=>' ')), 
    array('HtmlTag', array('tag' => 'li', 'class'=>'element')), 
); 

... मूल रूप से क्या होता है निम्नलिखित (वास्तविक वर्ग के नाम संक्षिप्तता के लिए छोटा कर दिया) है:

$decorator = new HtmlTag(new Label(new Errors(new Description(new ViewHelper())))); 
echo $decorator->render(); 

तो, अपने उदाहरण उत्पादन की जांच पर, हम होना चाहिए व्यक्तिगत सजावट के डिफ़ॉल्ट प्लेसमेंट व्यवहार को दूर करने में सक्षम:

// ViewHelper->render() 
<input type="text" name="title" id="title" value=""> 

// Description->render() 
<input type="text" name="title" id="title" value=""> 
<p class="hint">No --- way</p> // placement: append 

// Errors->render() 
<input type="text" name="title" id="title" value=""> 
<p class="hint">No --- way</p> 
<ul class="error"> // placement: append 
    <li>Value is required and cant be empty</li> 
</ul> 

// Label->render() 
<label for="title" class="required">Title</label> // placement: prepend 
<input type="text" name="title" id="title" value=""> 
<p class="hint">No --- way</p> 
<ul class="error"> 
    <li>Value is required and cant be empty</li> 
</ul> 

// HtmlTag->render() 
<li class="element"> // placement: wrap 
    <label for="title" class="required">Title</label> 
    <input type="text" name="title" id="title" value=""> 
    <p class="hint">No --- way</p> 
    <ul class="error"> 
     <li>Value is required and cant be empty</li> 
    </ul> 
</li> 

और आप क्या जानते हैं; यह वास्तव में सभी संबंधित सज्जाकारों की डिफ़ॉल्ट नियुक्ति है।

लेकिन अब कठिन हिस्सा आता है, आपको जो परिणाम दिख रहा है उसे पाने के लिए हमें क्या करने की ज़रूरत है? आदेश label और input हम बस ऐसा नहीं कर सकते लपेटो करने के लिए:

$decorate = array(
    array('ViewHelper'), 
    array('Description'), 
    array('Errors', array('class'=>'error')), 
    array('Label', array('tag'=>'div', 'separator'=>' ')), 
    array('HtmlTag', array('tag' => 'div')), // default placement: wrap 
    array('HtmlTag', array('tag' => 'li', 'class'=>'element')), 
); 
इस एक div के साथ सभी पूर्ववर्ती सामग्री ( ViewHelper, Description, Errors और Label), सही लपेट के रूप में

...? यहां तक ​​कि नहीं ... जोड़ा गया सजावटी अगले स्थान पर प्रतिस्थापित किया जाएगा, क्योंकि सजावटकर्ताओं को एक ही श्रेणी के होने पर निम्नलिखित सजावटकर्ता द्वारा प्रतिस्थापित किया जाता है।

$decorate = array(
    array('ViewHelper'), 
    array('Description'), 
    array('Errors', array('class'=>'error')), 
    array('Label', array('tag'=>'div', 'separator'=>' ')), 
    array(array('divWrapper' => 'HtmlTag'), array('tag' => 'div')), // we'll call it divWrapper 
    array('HtmlTag', array('tag' => 'li', 'class'=>'element')), 
); 

अब, हम अभी भी समस्या यह है कि divWrapper सभी पूर्ववर्ती सामग्री (ViewHelper, Description, Errors और Label) लपेट जाएगा के साथ सामना कर रहे हैं: जगह में आप यह एक अद्वितीय कुंजी देने के लिए करना होगा। तो हमें यहां रचनात्मक होने की जरूरत है। हम जो चाहते हैं उसे हासिल करने के कई तरीके हैं। मैं एक उदाहरण दे देंगे, कि शायद सबसे आसान है:

$decorate = array(
    array('ViewHelper'), 
    array('Label', array('tag'=>'div', 'separator'=>' ')), // default placement: prepend 
    array(array('divWrapper' => 'HtmlTag'), array('tag' => 'div')), // default placement: wrap 
    array('Description'), // default placement: append 
    array('Errors', array('class'=>'error')), // default placement: append 
    array('HtmlTag', array('tag' => 'li', 'class'=>'element')), // default placement: wrap 
); 

Zend_Form सज्जाकार मैं पढ़ Zend फ्रेमवर्क नेतृत्व डेवलपर मैथ्यू Weier O'Phinney के article about Zend Form Decorators

+0

वाह, यह कुछ पूरा जवाब है! अच्छा है ! –

+2

ओह वाह, मेरे पास उस जवाब में एक आह क्षण था, धन्यवाद और स्वीकार किया गया: डी –

+0

पी.एस. यह सबसे आश्चर्यजनक उत्तर था कि कभी भी –

2

प्रश्न # 1

बदलें सज्जाकार आदेश और एक HtmlTag सहायक इस तरह से जोड़ें:

$decorate = array(
    array('ViewHelper'), 
    array('Label', array('tag'=>'div', 'separator'=>' ')), 
    array('HtmlTag', array('tag' => 'div')), 
    array('Description'), 
    array('Errors', array('class'=>'error')), 
    array('HtmlTag', array('tag' => 'li', 'class'=>'element')) 
); 

प्रश्न # 2

डेकोरेटर एक श्रृंखला, के उत्पादन में कर रहे हैं प्रत्येक को 'सजाया' होने के लिए, अगले के इनपुट में पास किया जाता है।

डिफ़ॉल्ट रूप से, वे सामग्री (विवरण, त्रुटियां), सामग्री प्रस्तुत करें (लेबल ..) जोड़ते हैं और कुछ आसपास (एचटीएमटीएग) लपेटते हैं। लेकिन इन डिफ़ॉल्ट व्यवहार कर रहे हैं, और आप उनमें से ज्यादातर के लिए इसे बदल सकते हैं:

  1. ViewHelper यह है का उपयोग कर अपने फ़ॉर्म तत्व प्रस्तुत करता है:

    array('HtmlTag', array('tag' => 'span', placement=>'APPEND')); 
    //this would append <span></span> to the output of the previous decorator instead of wrapping it inside the <span> 
    

    की क्या अपनी श्रृंखला में क्या होता है के लिए एक अधिक करीब नजर है डिफ़ॉल्ट दृश्य हेल्पर, फॉर्म तत्व वर्ग में घोषित किया गया।

  2. Label पिछले उत्पादन के लिए लेबल

  3. HtmlTag लपेटता पहले जोड़ता एक जोड़ देती तत्वों वर्णन

  4. Errors त्रुटि संदेश जोड़ देती है, <div>

    आसपास
  5. Description यदि कोई

  6. HtmlTag एक <li>

संपादित

में यह सब लपेटता मैं कुछ भी परीक्षण के बिना इस जवाब लिखा, इसलिए कुछ छोटे अशुद्धियों यहाँ और वहाँ हो सकता है। प्रिय पाठक, अगर आप कुछ देखते हैं तो बस एक टिप्पणी छोड़ दें और मैं अपडेट करूंगा।

+0

अच्छा जवाब की सलाह देते हैं के बारे में अधिक विवरण के लिए और साथ ही निश्चित रूप से ! केवल चेतावनी यह है कि 'एचटीएमएलटीएजी' सजावटकर्ताओं में से एक या शायद दोनों (वास्तव में सुनिश्चित नहीं) को एक अद्वितीय कुंजी 'सरणी (' someUniqueKey '=>' HtmlTag ') के साथ जोड़ा जाना चाहिए, अन्यथा अंतिम पिछले को प्रतिस्थापित करेगा । –

+0

वाह धन्यवाद। ....: डी –

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