zend-framework zend-form decorator zend-view zend-form-element

zend framework - ¿Cómo uso ViewScripts en Zend_Form File Elements?



zend-framework zend-form (7)

Esta no es una solución simple o ideal porque requiere una extensión del decorador de archivos ... pero es bastante frustrante que no se hayan esforzado por separar la lógica de generación de elementos ocultos de la lógica de generación de entrada de archivos. No estoy seguro si el asistente de visualización de archivos maneja el problema de que un elemento sea una matriz (esa parece ser la razón por la que lo hicieron de esta manera).

Extensión de File Decorator: (la parte comentada es la que hace que se genere la entrada adicional).

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

Configuración de formulario en acción de controlador:

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

En vista de acción:

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

En la secuencia de comandos del 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>

La salida debería ser:

<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 esta solución es que los elementos ocultos no se procesan dentro de la secuencia de vistas; esto podría ser un problema si usa el div como selector en un script del lado del cliente ...

Estoy usando este ViewScript para mis elementos de formulario estándar:

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

Intentar utilizar solo ViewScript da como resultado un error:

Excepción atrapada por formulario: no se encontró el decorador de archivos ... no se puede procesar el elemento de archivo

Ver estas preguntas frecuentes reveló parte de mi problema, y ​​actualicé mis decoradores de elementos de formulario de esta manera:

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

Ahora está renderizando el elemento de archivo dos veces, una vez dentro de mi script de vista y elementos adicionales con el elemento de archivo fuera de mi script de vista:

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

¿Alguna idea sobre cómo manejar esto correctamente con un ViewScript?

ACTUALIZACIÓN: Basado en la solución de Shaun, aquí está mi código final:

Elemento de formulario:

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

Ver secuencia de comandos:

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


Lo más fácil es no añadir ningún marcado a la salida en su Decorador de archivos personalizado:

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

ahora puedes hacer lo que quieras en tu viewcript para este elemento de archivo (muestra el campo de entrada de archivo y todos los campos ocultos que necesitas por tu cuenta).


La respuesta es relativamente simple cuando sucede. Todo lo que necesita hacer es especificar primero el decorador de archivos, crear un script de vista específico para la entrada del archivo y especificar false para la ubicación en los argumentos del decorador de viewScript, esto inyectará efectivamente el resultado del decorador de archivos en el decorador viewScript.

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

Luego, en el nuevo script de vista de elemento de archivo, simplemente hace eco de $ this-> content en el script donde desea colocar el marcado de entrada de archivo. Aquí hay un ejemplo de un proyecto reciente, así que ignore el marcado si se ve un poco extraño, con suerte lo ilustrará.

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

Cuando se represente, verá este html para el 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>


Esto me ayudó a solucionar mi problema. Ajusté el código para envolver el elemento de archivo dentro de una tabla. Para que funcione, simplemente elimine la etiqueta del viewdecorator y agregue el elemento de archivo de la siguiente manera:

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


Lo que me di cuenta es que una clase de decorador personalizado manejará la mayoría de los campos, excepto los campos Archivo. Asegúrate de que tu clase implemente la interfaz de la siguiente manera:

class CC_Form_Decorator_Pattern extends Zend_Form_Decorator_Abstract implements Zend_Form_Decorator_Marker_File_Interface

Esto funcionó para mí.


En caso de que hayas seguido la respuesta de @Shaun y sigas recibiendo el error: asegúrate de haber deshabilitado los decoradores por defecto para el elemento en cuestión (mira la línea 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),), ));


Encontré una alternativa que evita el ViewScript por completo.

Primero, la definición del 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(), ));

En segundo lugar, después de que se haya instanciado la clase de formulario, imito el comportamiento de mi 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);

Supongo que debería buscar decoradores basados ​​en clases. Tal vez hay más flexibilidad allí?