Подтвердить что ты не робот

Как использовать ViewScripts для элементов файла Zend_Form?

Я использую этот 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 приводит к ошибке:

Исключение, пойманное по форме: Нет файла декоратор нашел... не в состоянии сделать файловый элемент

Глядя на этот FAQ, я обнаружил часть своей проблемы, и я обновил свои декораторы элементов формы следующим образом:

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

Теперь он дважды отображает элемент файла один раз в моем представлении script и дополнительные элементы с элементом файла вне моего представления 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>

Любые идеи о том, как правильно обращаться с 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),),
));

Просмотр 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>
4b9b3361

Ответ 1

Ответ относительно прост, как это происходит. Все, что вам нужно сделать, это сначала указать декоратор файлов, создать определенный вид script для ввода файла и указать значение false для места размещения в аргументах декоратора viewScript, это будет эффективно вводить результат из декоратора File в декоратор вида, например

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

Затем в новом представлении элемента файла script вы просто эхо файл $this- > в script, где вы хотите разместить разметку ввода файла. Вот пример из недавнего проекта, поэтому игнорируйте разметку, если она выглядит немного странно, надеюсь, это проиллюстрирует точку.

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

Ответ 2

Это не простое или идеальное решение, потому что оно требует расширения Декоратора Файлов... но это довольно разочаровывает, что они не прилагают усилий, чтобы отделить логику генерации скрытого элемента от логики генерации входного файла. Я не уверен, что помощник представления файлов справляется с проблемой того, что элемент является массивом (это, по-видимому, причина, по которой они сделали это таким образом.)

Расширение файлового декоратора: (закомментированная часть - это то, что вызывает создание дополнительного ввода.)

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

В элементе script:

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

Проблема с этим решением заключается в том, что скрытые элементы не отображаются внутри viewcript; это может быть проблемой, если вы используете div как селектор на стороне клиента script...

Ответ 3

Я понял, что пользовательский класс декоратора будет обрабатывать большинство полей, кроме полей File. Убедитесь, что ваш класс реализует интерфейс следующим образом:

class CC_Form_Decorator_Pattern 
extends Zend_Form_Decorator_Abstract 
implements Zend_Form_Decorator_Marker_File_Interface

Это сработало для меня.

Ответ 4

Это помогло мне исправить мою проблему. Я скорректировал код, чтобы обернуть элемент файла внутри таблицы. Чтобы он работал, просто удалите метку из viewdecorator и добавьте элемент файла следующим образом:

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

Ответ 5

Я нашел обход, который полностью избегает 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);

Я предполагаю, что я должен изучить декораторы на основе классов. Может быть, там больше гибкости?

Ответ 6

Проще всего сделать это, чтобы не добавлять разметку к выходу в вашем обычном Decorator файла:

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

теперь вы можете делать все, что хотите, в своем viewcript для этого элемента файла (выведите поле ввода файла и все скрытые поля, которые вам нужны сами).

Ответ 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),),
));