19

Ich bin mit diesem Viewscript für meine Standard-Formularelemente:Wie verwende ich ViewScripts auf Zend_Form Datei-Elemente?

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

Des Versuch allein führt zu einem Fehler zu verwenden, das Viewscript:

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

Mit Blick auf this FAQ Teil meines Problems offenbart, und ich aktualisierte mein Formelement Dekorateure wie folgt aus:

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

nun in meiner Ansicht zweimal die Datei Element Rendering, sobald es Skript und zusätzliche Elemente mit dem Dateielement außerhalb meiner Ansicht Skript:

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

Alle Ideen, wie dies mit einem Viewscript richtig zu handhaben?


UPDATE: Basierend auf Shaun-Lösung, hier ist meine letzte Code:

Formular Element:

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

Skript anzeigen:

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

Antwort

19

Die Antwort ist relativ einfach, wie es passiert. Alles, was Sie tun müssen, ist, zuerst den Datei-Decorator anzugeben, ein spezifisches View-Skript für die Dateieingabe zu erstellen und false für die Platzierung in den ViewScript-Decorator-Argumenten anzugeben, wodurch die Ausgabe des File Decorator effektiv in den ViewScript-Decorator z.

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

Dann in dem neuen Datei Element View Skript echo Sie einfach $ this-> Inhalt im Skript, in dem Sie die Datei Eingabe Markup mögen platziert werden. Hier ist ein Beispiel aus einem kürzlichen Projekt, also ignoriere das Markup, wenn es ein wenig seltsam aussieht, hoffentlich wird es den Punkt verdeutlichen.

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

Beim Rendern Sie diesen HTML für das Element sehen

<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

Das sieht genau danach aus, was ich suche. Ich versuche es und markiere deine als Antwort, wenn es so funktioniert, wie ich es brauche! – Sonny

+0

Ich habe gerade Ihre Lösung getestet, und es funktioniert! Danke Shaun! – Sonny

+0

Ich wollte Ihnen nur noch einmal danken, das ist so viel besser als meine vorherige Lösung. – Sonny

4

Dies ist keine einfache oder ideale Lösung, weil sie eine Erweiterung des File decorator erfordert ... aber es ist ziemlich frustrierend, dass sie nicht die Mühe machen, haben die versteckte Element Erzeugungslogik aus der Datei-Eingabe-Erzeugungslogik zu trennen. Ich bin nicht sicher, ob die Datei View Helfer das Problem eines Elements behandelt ein Array sein

Erweiterung der Datei Decorator (das scheint der Grund, warum sie es auf diese Weise tat zu sein.): (die auf Kommentar Teil ist, was die zusätzliche Eingabe erzeugt werden)

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

    } 

    } 

} 

?> 

Formular-Setup in Controller-Aktion verursacht.

$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 Aktion Ausblick:

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

In Element Skript:

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

ausgegeben werden soll:

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

Ein Problem bei dieser Lösung ist, dass die verborgenen Elemente machen nicht innerhalb des Viewscript; dies könnte ein Problem sein, wenn Sie die div als Selektor in einem clientseitige Skript verwenden ...

+0

Dank für den Vorschlag Robin, aber "keine Datei Dekorator" Ausnahme wird geworfen, wenn es so auch tut. – Sonny

+0

Das ist wirklich merkwürdig. Ich habe es getestet, bevor ich meine Antwort gepostet habe, und es funktioniert immer noch für mich. –

+0

Mit Zend 1.96 übrigens. Ich weiß nicht, ob das in diesem Fall einen Unterschied machen würde oder nicht. –

0

Ich habe eine Behelfslösung gefunden, die das Viewscript ganz vermeidet.

Zunächst wird die Elementdefinition:

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

Zweitens, nachdem die Formularklasse instanziert wurde, imitieren ich das Verhalten meiner 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); 

Ich denke, dass ich in die Klasse aussehen sollte -basierte Dekorateure. Vielleicht gibt es dort mehr Flexibilität?

+0

Ich möchte diese Frage offen lassen, falls es einen Weg gibt, es mit einem ViewScript zu machen. – Sonny

0

Die einfachste Sache zu tun ist kein Markup überhaupt an den Ausgang in der benutzerdefinierten Datei Decorator hinzuzufügen:

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

jetzt können Sie tun, was Sie für diese Datei Element in Ihrem Viewscript wollen (Ausgabe die Datei Eingabefeld und alle versteckten Felder, die Sie selbst benötigen).

+0

Ich hatte keine Chance, Ihre Lösung zu versuchen. Ich möchte alle versteckten Felder, die vom Framework bereitgestellt werden, ich wollte sie nur in meine bevorzugten HTML-Elemente einfügen. Löst Ihre Lösung das? – Sonny

1

Das half mir, mein Problem zu beheben. Ich habe den Code angepasst, um das Dateielement in eine Tabelle zu schreiben. Um es Arbeit zu machen, entfernen Sie einfach das Etikett von der viewdecorator und fügen Sie die Datei Element wie folgt:

$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

Was habe ich realisiert, wird eine benutzerdefinierte Dekorateur-Klasse die meisten Felder außer Dateifelder bearbeiten. Achten Sie auf die Schnittstelle wie so Ihre Klasse implementiert:

class CC_Form_Decorator_Pattern 
extends Zend_Form_Decorator_Abstract 
implements Zend_Form_Decorator_Marker_File_Interface 

Das ist für mich gearbeitet.

+0

Das wäre ein klassenbasierter Dekorator, statt eines View-Skripts, oder? – Sonny

0

Nur für den Fall haben Sie @ Shaun Antwort gefolgt und Sie immer noch den Fehler bekommen: stellen Sie sicher, dass Sie deaktiviert Standarddekorator für das Element in Frage haben (nehmen Blick auf Linie 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),), 
));