19

Sto usando questo ViewScript per i miei elementi di modulo standard:Come utilizzare ViewScripts su elementi file Zend_Form?

<div class="field" id="field_<?php echo $this->element->getId(); ?>"> 
    <?php if (0 < strlen($this->element->getLabel())) : ?> 
     <?php echo $this->formLabel($this->element->getName(), $this->element->getLabel());?> 
    <?php endif; ?> 
    <span class="value"><?php echo $this->{$this->element->helper}(
     $this->element->getName(), 
     $this->element->getValue(), 
     $this->element->getAttribs() 
    ) ?></span> 
    <?php if (0 < $this->element->getMessages()->length) : ?> 
     <?php echo $this->formErrors($this->element->getMessages()); ?> 
    <?php endif; ?> 
    <?php if (0 < strlen($this->element->getDescription())) : ?> 
     <span class="hint"><?php echo $this->element->getDescription(); ?></span> 
    <?php endif; ?> 
</div> 

Cercando di utilizzare tale ViewScript solo i risultati in un errore:

Exception caught by form: No file decorator found... unable to render file element

Guardando this FAQ rivelato parte del mio problema, e ho aggiornato i miei decoratori di elementi di forma come questo:

'decorators' => array(
    array('File'), 
    array('ViewScript', array('viewScript' => 'form/field.phtml')) 
) 

Ora esegue il rendering dell'elemento di file due volte, una volta all'interno della visualizzazione script e elementi extra con l'elemento del file fuori dalla mia vista script:

<input type="hidden" name="MAX_FILE_SIZE" value="8388608" id="MAX_FILE_SIZE" /> 
<input type="hidden" name="UPLOAD_IDENTIFIER" value="4b5f7335a55ee" id="progress_key" /> 
<input type="file" name="upload_file" id="upload_file" /> 
<div class="field" id="field_upload_file"> 
    <label for="upload_file">Upload File</label> 
    <span class="value"><input type="file" name="upload_file" id="upload_file" /></span> 
</div> 

Tutte le idee su come gestire questo correttamente con un ViewScript?


UPDATE: Sulla base di soluzione di Shaun, ecco il mio codice finale:

Forma Elemento:

$this->addElement('file', 'upload_file', array(
    'disableLoadDefaultDecorators' => true, 
    'decorators' => array('File', array('ViewScript', array(
     'viewScript' => '_form/file.phtml', 
     'placement' => false, 
    ))), 
    'label' => 'Upload', 
    'required' => false, 
    'filters' => array(), 
    'validators' => array(array('Count', false, 1),), 
)); 

Visualizza script:

<?php 
$class .= 'field ' . strtolower(end(explode('_',$this->element->getType()))); 
if ($this->element->isRequired()) { 
    $class .= ' required'; 
} 
if ($this->element->hasErrors()) { 
    $class .= ' errors'; 
} 
?> 
<div class="<?php echo $class; ?>" id="field_<?php echo $this->element->getId(); ?>"> 
    <?php if (0 < strlen($this->element->getLabel())): ?> 
     <?php echo $this->formLabel($this->element->getFullyQualifiedName(), $this->element->getLabel());?> 
    <?php endif; ?> 
    <span class="value"><?php echo $this->content; ?></span> 
    <?php if ($this->element->hasErrors()): ?> 
     <?php echo $this->formErrors($this->element->getMessages()); ?> 
    <?php endif; ?> 
    <?php if (0 < strlen($this->element->getDescription())): ?> 
     <p class="hint"><?php echo $this->element->getDescription(); ?></p> 
    <?php endif; ?> 
</div> 

risposta

19

La risposta è relativamente semplice come accade. Tutto ciò che devi fare è specificare innanzitutto il decoratore di file, creare uno script di visualizzazione specifico per l'input del file e specificare false per il posizionamento negli argomenti del decoratore di viewScript, questo in effetti inietterà l'output dal decoratore di file nel decorator di viewScript, ad es.

$element->setDecorators(array('File', array('ViewScript', array('viewScript' => 'decorators/file.phtml', 'placement' => false)))); 

Poi nel nuovo script di visualizzazione elemento del file è sufficiente echo $ this-> contenuti nello script in cui si desidera il markup di ingresso di file da posizionare. Ecco un esempio di un progetto recente, quindi ignorare il markup se sembra un po 'strano, si spera che illustri il punto.

<label for="<?php echo $this->element->getName(); ?>" class="element <?php if ($this->element->hasErrors()): ?> error<?php endif; ?>" id="label_<?php echo $this->element->getName(); ?>"> 
<span><?php echo $this->element->getLabel(); ?></span> 

<?php echo $this->content; ?> 

<?php if ($this->element->hasErrors()): ?> 

    <span class="error"> 
     <?php echo $this->formErrors($this->element->getMessages()); ?> 
    </span> 

<?php endif; ?> 

</label> 

se fusi si vedrà questo html per l'elemento

<label for="photo" class="element" id="label_photo"> 
<span>Photo</span> 

<input type="hidden" name="MAX_FILE_SIZE" value="6291456" id="MAX_FILE_SIZE"> 
<input type="file" name="photo" id="photo"> 

</label> 
+0

Questo sembra esattamente quello che sto cercando. Lo provo e segnalo come risposta se funziona come ne ho bisogno! – Sonny

+0

Ho appena testato la tua soluzione e funziona! Grazie Shaun! – Sonny

+0

Volevo solo ringraziarvi ancora, è molto meglio della mia precedente soluzione. – Sonny

4

Questo non è un semplice o soluzione ideale perché richiede un'estensione del decoratore di file ... ma è piuttosto frustrante che non abbiano fatto lo sforzo di separare la logica di generazione di elementi nascosti dalla logica di generazione di input di file. Non sono sicuro se l'helper vista dei file gestisce l'emissione di un elemento essendo una matrice

Estensione del Decorator File (che sembra essere la ragione per cui lo ha fatto in questo modo.): (la parte commentata è ciò che provoca l'ingresso supplementare da generare) configurazione

<?php 

class Sys_Form_Decorator_File extends Zend_Form_Decorator_File { 

    public function render($content) { 

    $element = $this->getElement(); 
    if (!$element instanceof Zend_Form_Element) {return $content;} 

    $view = $element->getView(); 
    if (!$view instanceof Zend_View_Interface) {return $content;} 

    $name = $element->getName(); 
    $attribs = $this->getAttribs(); 
    if (!array_key_exists('id', $attribs)) {$attribs['id'] = $name;} 

    $separator = $this->getSeparator(); 
    $placement = $this->getPlacement(); 
    $markup = array(); 
    $size = $element->getMaxFileSize(); 

    if ($size > 0) { 

     $element->setMaxFileSize(0); 
     $markup[] = $view->formHidden('MAX_FILE_SIZE', $size); 

    } 

    if (Zend_File_Transfer_Adapter_Http::isApcAvailable()) { 

     $apcAttribs = array('id' => 'progress_key'); 
     $markup[] = $view->formHidden('APC_UPLOAD_PROGRESS', uniqid(), $apcAttribs); 

    } 

    else if (Zend_File_Transfer_Adapter_Http::isUploadProgressAvailable()) { 

     $uploadIdAttribs = array('id' => 'progress_key'); 
     $markup[] = $view->formHidden('UPLOAD_IDENTIFIER', uniqid(), $uploadIdAttribs); 

    } 

    /* 

    if ($element->isArray()) { 

     $name .= "[]"; 
     $count = $element->getMultiFile(); 

     for ($i = 0; $i < $count; ++$i) { 

     $htmlAttribs = $attribs; 
     $htmlAttribs['id'] .= '-' . $i; 
     $markup[] = $view->formFile($name, $htmlAttribs); 

     } 

    } 

    else {$markup[] = $view->formFile($name, $attribs);} 

    */ 

    $markup = implode($separator, $markup); 

    switch ($placement) { 

     case self::PREPEND: return $markup . $separator . $content; 
     case self::APPEND: 
     default: return $content . $separator . $markup; 

    } 

    } 

} 

?> 

Forma in azione del controller.

$form = new Zend_Form(); 
$form->addElement(new Zend_Form_Element_File('file')); 
$form->file->setLabel('File'); 
$form->file->setDescription('Description goes here.'); 

$decorators = array(); 
$decorators[] = array('File' => new Sys_Form_Decorator_File()); 
$decorators[] = array('ViewScript', array('viewScript' => '_formElementFile.phtml')); 
$form->file->setDecorators($decorators); 

$this->view->form = $form; 

in azione Vista:

<?php echo $this->form; ?> 

Nella sceneggiatura elemento:

<div class="field" id="field_<?php echo $this->element->getId(); ?>"> 

<?php if (0 < strlen($this->element->getLabel())) : ?> 
<?php echo $this->formLabel($this->element->getName(), $this->element->getLabel());?> 
<?php endif; ?> 

<span class="value"> 
<?php 

echo $this->{$this->element->helper}(

    $this->element->getName(), 
    $this->element->getValue(), 
    $this->element->getAttribs() 

); 

?> 
</span> 

<?php if (0 < $this->element->getMessages()->length) : ?> 
<?php echo $this->formErrors($this->element->getMessages()); ?> 
<?php endif; ?> 

<?php if (0 < strlen($this->element->getDescription())) : ?> 
<span class="hint"><?php echo $this->element->getDescription(); ?></span> 
<?php endif; ?> 

</div> 

uscita dovrebbe essere:

<form enctype="multipart/form-data" action="" method="post"> 
<dl class="zend_form"> 
<input type="hidden" name="MAX_FILE_SIZE" value="134217728" id="MAX_FILE_SIZE" /> 
<div class="field" id="field_file"> 
<label for="file">File</label> 
<span class="value"><input type="file" name="file" id="file" /></span> 
<span class="hint">Description goes here.</span> 
</div> 
</dl> 
</form> 

Un problema con questa soluzione è che gli elementi nascosti non rendono all'interno dello script; questo potrebbe essere un problema se stai usando il div come selettore in uno script lato client ...

+0

Grazie per il suggerimento Robin, ma l'eccezione "nessun decoratore di file" viene lanciata quando lo fa anche in quel modo. – Sonny

+0

Questo è davvero strano. L'ho provato prima di pubblicare la mia risposta, e funziona ancora per me. –

+0

Utilizzando Zend 1.96, a proposito. Non so se questo potrebbe fare la differenza in questo caso o no. –

0

Ho trovato un work-around che evita del tutto il ViewScript.

In primo luogo, la definizione elemento:

$this->addElement('file', 'upload_file', array(
    'disableLoadDefaultDecorators' => true, 
    'decorators' => array(
     'File', 
     array(array('Value'=>'HtmlTag'), array('tag'=>'span','class'=>'value')), 
     'Errors', 
     'Description', 
     'Label', 
     array(array('Field'=>'HtmlTag'), array('tag'=>'div','class'=>'field file')), 
    ), 
    'label' => 'Upload File', 
    'required' => false, 
    'filters' => array('StringTrim'), 
    'validators' => array(), 
)); 

In secondo luogo, dopo che la classe del form è stata creata un'istanza, ho imitare il comportamento del mio ViewScript:

$field = $form->getElement('upload_file'); 
$decorator = $field->getDecorator('Field'); 
$options = $decorator->getOptions(); 
$options['id'] = 'field_' . $field->getId(); 
if ($field->hasErrors()) { 
    $options['class'] .= ' errors'; 
} 
$decorator->setOptions($options); 

Credo che dovrei guardare in classe decoratori Forse c'è più flessibilità lì?

+0

Voglio lasciare questa domanda aperta, nel caso ci sia un modo per farlo con un ViewScript. – Sonny

0

La cosa più semplice da fare è aggiungere nessuna marcatura a tutti per l'output nel tuo Decorator file personalizzato:

class Custom_Form_Decorator_File extends Zend_Form_Decorator_File { 
     public function render($content) { 
       return $content; 
     } 
}

ora si può fare quello che vuoi nella vostra ViewScript per questo elemento del file (l'output del file campo di immissione e tutti i campi nascosti di cui hai bisogno da solo).

+0

Non ho avuto la possibilità di provare la soluzione. Voglio tutti i campi nascosti forniti dal framework, volevo semplicemente includerli nei miei elementi HTML preferiti. La tua soluzione lo realizza? – Sonny

1

Questo mi ha aiutato a risolvere il mio problema. Ho modificato il codice per avvolgere l'elemento file all'interno di un tavolo. Per farlo funzionare, è sufficiente rimuovere l'etichetta dal viewdecorator e aggiungere l'elemento file come segue:

$form->addElement('file', 'upload_file', array(
     'disableLoadDefaultDecorators' => true, 
     'decorators' => array(
      'Label', 
      array(array('labelTd' => 'HtmlTag'), array('tag' => 'td', 'class' => 'labelElement')), 
      array(array('elemTdOpen' => 'HtmlTag'), array('tag' => 'td', 'class' => 'dataElement','openOnly' => true, 'placement' => 'append')), 
      'File', 
      array('ViewScript', array(
      'viewScript' => 'decorators/file.phtml', 
      'placement' => false, 
      )), 
      array(array('elemTdClose' => 'HtmlTag'), array('tag' => 'td', 'closeOnly' => true, 'placement' => 'append')), 
      array(array('row' => 'HtmlTag'), array('tag' => 'tr')) 
     ), 
     'label' => 'Upload', 
     'required' => false, 
     'filters' => array(), 
     'validators' => array(array('Count', false, 1),), 
    )); 
2

Quello che ho capito è, una classe decoratrice personalizzato gestire la maggior parte i campi ad eccezione dei campi di file. Assicurati che il tuo classe implementa l'interfaccia in questo modo:

class CC_Form_Decorator_Pattern 
extends Zend_Form_Decorator_Abstract 
implements Zend_Form_Decorator_Marker_File_Interface 

Questo ha funzionato per me.

+0

Questo sarebbe un decoratore basato su classi, invece di uno script di visualizzazione, giusto? – Sonny

0

Solo nel caso in cui si hanno seguito @ risposta di Shaun e si sta ancora ricevendo l'errore: fare in modo che hai abili decoratori di default per l'elemento in questione (prendere guarda linea 2):

$this->addElement('file', 'upload_file', array(
'disableLoadDefaultDecorators' => true, 
'decorators' => array('File', array('ViewScript', array(
    'viewScript' => '_form/file.phtml', 
    'placement' => false, 
))), 
'label' => 'Upload', 
'required' => false, 
'filters' => array(), 
'validators' => array(array('Count', false, 1),), 
));