【问题标题】:How do I use ViewScripts on Zend_Form File Elements?如何在 Zend_Form 文件元素上使用 ViewScripts?
【发布时间】:2011-01-09 18:01:04
【问题描述】:

我将这个 ViewScript 用于我的标准表单元素:

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

尝试单独使用该 ViewScript 会导致错误:

表单捕获的异常:没有文件 发现装饰器...无法渲染 文件元素

查看this FAQ 揭示了我的部分问题,我更新了我的表单元素装饰器,如下所示:

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

现在它会渲染文件元素两次,一次在我的视图脚本中,以及在我的视图脚本之外的文件元素的额外元素:

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

关于如何使用 ViewScript 正确处理此问题的任何想法?


更新:基于 Shaun 的解决方案,这是我的最终代码:

表单元素:

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

查看脚本:

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

【问题讨论】:

    标签: zend-framework zend-form decorator zend-view zend-form-element


    【解决方案1】:

    这不是一个简单或理想的解决方案,因为它需要扩展文件装饰器......但令人沮丧的是,他们没有努力将隐藏元素生成逻辑与文件输入生成逻辑分开。我不确定文件视图助手是否处理元素是数组的问题(这似乎是他们这样做的原因。)

    文件装饰器的扩展: (注释掉的部分是导致生成额外输入的原因。)

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

    控制器动作中的表单设置:

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

    在行动视图中:

    <?php echo $this->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>
    

    输出应该是:

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

    这个解决方案的一个问题是隐藏元素不在视图脚本中呈现;如果您在客户端脚本中使用 div 作为选择器,这可能是个问题...

    【讨论】:

    • 感谢 Robin 的建议,但这样做也会引发“无文件装饰器”异常。
    • 这真的很奇怪。我在发布答案之前对其进行了测试,它仍然对我有用。
    • 顺便说一下,使用 Zend 1.96。我不知道在这种情况下这是否会有所不同。
    • 我使用的是 1.9.7,所以这可能是个问题。我再次尝试确认,但得到了同样的错误。
    • 我知道我做错了什么,以及为什么我收到错误,但您的解决方案没有将“文件”装饰器的输出包装在 ViewScript 装饰器中。它首先呈现,然后是 ViewScript 输出,类似于我上面的输出示例。
    【解决方案2】:

    我找到了一种完全避免使用 ViewScript 的解决方法。

    一、元素定义:

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

    其次,在窗体类被实例化后,我模仿我的 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);
    

    我想我应该研究基于类的装饰器。也许那里有更多的灵活性?

    【讨论】:

    • 我想保留这个问题,以防万一有办法使用 ViewScript。
    【解决方案3】:

    最简单的做法是在自定义文件装饰器的输出中完全不添加任何标记:

    类 Custom_Form_Decorator_File 扩展 Zend_Form_Decorator_File {
            公共功能渲染($内容){
                    返回$内容;
            }
    }

    现在您可以在视图脚本中为此文件元素做任何您想做的事情(输出文件输入字段和您自己需要的所有隐藏字段)。

    【讨论】:

    • 我没有机会尝试您的解决方案。我确实想要框架提供的所有隐藏字段,我只想将它们包装在我喜欢的 HTML 元素中。你的解决方案能做到吗?
    【解决方案4】:

    答案相对简单。您需要做的就是首先指定 File 装饰器,为文件输入创建一个特定的视图脚本,并在 viewScript 装饰器参数中为放置指定 false,这将有效地将 File 装饰器的输出注入到 viewScript 装饰器中,例如

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

    然后在新的文件元素视图脚本中,您只需在脚本中回显 $this->content 您希望放置文件输入标记的位置。这是最近一个项目的一个例子,如果标记看起来有点奇怪,请忽略它,希望它能说明这一点。

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

    渲染后,您将看到该元素的 html

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

    【讨论】:

    • 这看起来正是我正在寻找的。如果它可以满足我的需要,我会尝试并将您的标记为答案!
    • 我只是想再次感谢您,这比我之前的解决方案好多了。
    【解决方案5】:

    这帮助我解决了我的问题。我调整了代码以将文件元素包装在表格中。要使其工作,只需从视图装饰器中删除标签并添加文件元素,如下所示:

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

    【讨论】:

      【解决方案6】:

      我意识到,自定义装饰器类将处理除文件字段之外的大多数字段。 确保你的类实现了这样的接口:

      class CC_Form_Decorator_Pattern 
      extends Zend_Form_Decorator_Abstract 
      implements Zend_Form_Decorator_Marker_File_Interface
      

      这对我有用。

      【讨论】:

      • 这将是一个基于类的装饰器,而不是视图脚本,对吧?
      【解决方案7】:

      以防万一您遵循了@Shaun 的回答,但您仍然收到错误:确保您已禁用相关元素的默认装饰器(查看第 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),),
      ));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-21
        • 2010-09-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多