19

J'utilise ce ViewScript pour mes éléments standards:Comment utiliser ViewScripts sur les éléments de fichier 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> 

Essayer d'utiliser cette ViewScript seul provoque une erreur:

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

regardant this FAQ a révélé une partie de mon problème, et je mis à jour mes décorateurs d'éléments de formulaire aiment ceci:

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

Maintenant, il rend l'élément de fichier deux fois, une fois dans ma vue script et éléments supplémentaires avec l'élément de fichier en dehors de mon script de vue:

<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> 

Toutes les idées sur la façon de gérer cela correctement avec un ViewScript?


MISE À JOUR: Sur la base de la solution de Shaun, voici mon code final:

Forme élément:

$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),), 
)); 

Afficher le 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> 

Répondre

19

La réponse est relativement simple que cela arrive. Tout ce que vous devez faire est d'abord spécifier le décorateur de fichiers, créer un script de vue spécifique pour l'entrée du fichier et spécifier false pour le placement dans les arguments du décorateur viewScript, cela va effectivement injecter la sortie du décorateur de fichiers dans le décorateur viewScript.

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

Ensuite, dans le nouveau script de vue des éléments de fichier echo simplement $ this-> contenu dans le script où vous souhaitez le balisage d'entrée de fichier à placer. Voici un exemple d'un projet récent, donc ignorez le balisage si cela semble un peu étrange, j'espère que cela illustrera le point.

<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> 

Lorsque rendiez vous verrez ce code HTML pour l'élément

<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

Cela ressemble exactement à ce que je cherche. Je l'essaie et marque le vôtre comme la réponse si cela fonctionne comme j'en ai besoin! – Sonny

+0

Je viens de tester votre solution, et cela fonctionne! Merci Shaun! – Sonny

+0

Je voulais juste vous remercier à nouveau, c'est tellement mieux que ma solution précédente. – Sonny

4

Ce n'est pas simple ou solution idéale car elle nécessite une extension du File décorator ... mais il est plutôt frustrant qu'ils n'aient pas fait l'effort de séparer la logique de génération d'éléments cachés de la logique de génération d'entrée de fichier. Je ne sais pas si l'affichage des fichiers aide traite la question d'un élément étant un tableau

Extension du décorateur de fichier (qui semble être la raison pour laquelle ils l'ont fait de cette façon.): (la partie commentée est ce qui provoque l'entrée supplémentaire à générer)

<?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; 

    } 

    } 

} 

?> 

configuration de formulaire dans l'action du contrôleur.

$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; 

dans l'action Vue:

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

En script élément:

<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> 

sortie doit être:

<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 problème avec cette solution est que les éléments cachés ne rendent pas dans le viewscript; Cela peut être un problème si vous utilisez le div comme un sélecteur dans un script côté client ...

+0

Merci pour la suggestion de Robin, mais l'exception «pas de décorateur de fichier» est levée quand on le fait aussi. – Sonny

+0

C'est vraiment étrange. Je l'ai testé avant de poster ma réponse, et ça marche toujours pour moi. –

+0

En utilisant Zend 1.96, au fait. Je ne sais pas si cela ferait une différence dans ce cas ou non. –

0

J'ai trouvé une solution qui évite complètement le ViewScript.

D'abord, la définition de l'élément:

$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(), 
)); 

En second lieu, après la classe de formulaire a été instancié, j'imite le comportement de mon 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); 

Je suppose que je devrais regarder dans la classe décorateurs à base de Peut-être qu'il y a plus de flexibilité là-bas?

+0

Je veux laisser cette question ouverte, au cas où il y aurait un moyen de le faire avec un ViewScript. – Sonny

0

La meilleure chose à faire est d'ajouter sans majoration du tout à la sortie de votre décorateur de fichier personnalisé:

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

vous pouvez maintenant faire tout ce que vous voulez dans votre ViewScript pour cet élément de fichier (sortie le fichier champ de saisie et tous les champs cachés dont vous avez besoin vous-même).

+0

Je n'ai pas eu l'occasion d'essayer votre solution. Je veux tous les champs cachés fournis par le framework, je voulais juste les placer dans mes éléments HTML préférés. Est-ce que votre solution accomplit cela? – Sonny

1

Cela m'a aidé à résoudre mon problème. J'ai ajusté le code pour envelopper l'élément de fichier dans une table. Pour le faire fonctionner, il suffit d'enlever l'étiquette de la viewdecorator et ajouter l'élément de fichier comme suit:

$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

Ce que je me suis rendu compte est, une classe de décorateur personnalisé manipulera la plupart des champs à l'exception des champs de fichiers. Assurez-vous que votre classe implémente l'interface comme ceci:

class CC_Form_Decorator_Pattern 
extends Zend_Form_Decorator_Abstract 
implements Zend_Form_Decorator_Marker_File_Interface 

Cela a fonctionné pour moi.

+0

Ce serait un décorateur basé sur la classe, au lieu d'un script de vue, non? – Sonny

0

Juste au cas où vous avez suivi @ réponse de Shaun et vous obtenez toujours l'erreur: assurez-vous que vous avez décorateurs par défaut handicapés pour l'élément en question (prendre, regardez à la ligne 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),), 
));