【问题标题】:Change dynamically validated_file_class in symfony 1.4在 symfony 1.4 中更改动态验证文件类
【发布时间】:2013-02-26 21:07:46
【问题描述】:

我有这个模型:

Banner:
 columns:
  filename: string(255)
  url: string(255)
  position:
   type: enum
   values: [top, right]
   default: right

还有这个表格:

class BannerForm extends BaseBannerForm
{
  public function configure()
  {
    $this->widgetSchema['filename'] = new sfWidgetFormInputFileEditable(array(
      'file_src' => $this->getObject()->getThumbURL(),
      'is_image' => true,
      'edit_mode' => $this->getObject()->exists()
    ));
    $validated_file_class = $this->getObject()->position === 'right' ? 'bannerRightValidatedFile' : 'bannerTopValidatedFile';
    $this->validatorSchema['filename'] = new sfValidatorFile(array(
      'path' => sfConfig::get('sf_upload_dir'),
      'mime_types' => 'web_images',
      'validated_file_class' => $validated_file_class',
      'required' => $this->getObject()->isNew()
    ));
  }
}

我使用不同的验证类,因为在其中我封装了缩略图操作,并且横幅的大小取决于它的位置字段。 问题是 $validated_file_class 始终是 bannerRightValidatedFile 类。 我怎样才能做到这一点?

【问题讨论】:

  • 作为替代解决方案,您可以将图像调整大小放入Banner 类的preSavepostSave 方法中,而无需使用验证器@kirugan
  • @1ed 是的,我可以,但我认为这会导致代码错误
  • 你为什么这么认为?我认为它比下面提到的验证器黑客要干净得多。
  • 我更喜欢所有相同登录在一个地方的方式(在我的情况下是验证逻辑和一些特定的回调),将来可能很难重构您建议的代码样式。就个人而言,我使用 preSave 和 postSave 来处理与模型本身相关的事情。
  • 我认为这不是验证逻辑,只是根据模型对象的当前状态调整文件大小......但无论如何,如果你想把它放在表单中,那么你应该更改验证文件类就在处理上传的文件之前。您可以通过覆盖processValues 方法或通过添加updateFilenameColumn 方法更好地做到这一点。如果您有兴趣,我可以发布一个答案。

标签: forms symfony1 validation symfony-1.4


【解决方案1】:

我可以推荐 4 种解决方案供您选择:

选项 1:

您应该在表单类中添加一个 update$fieldNameColumn 方法。在您的情况下,它应该如下所示:

// change validated file instance before calling save
protected function updateFilenameColumn($value)
{
  if ($value instanceof sfValidatedFile)
  {
    $class = 'right' == $this->getValue('position') ? 'bannerRightValidatedFile' : 'bannerTopValidatedFile';
    // this will not work as I thought at first time
    // $this->getValidator('filename')->setOption('validated_file_class', $class);

    $this->values['filename'] = new $class(
      $value->getOriginalName(),
      $value->getType(),
      $value->getTempName(),
      $value->getSize(),
      $value->getPath()
    );

    return $this->processUploadedFile('filename');
  }

  return $value;
}

我觉得这有点骇人听闻。

选项 2:

您应该在模型中添加一个教义挂钩方法:

/**
 * @param Doctrine_Event $event
 */
public function postSave($event)
{
  $record = $event->getInvoker();

  if (array_key_exists('filename', $record->getLastModified()))
  {
    // get the full path to the file
    $file = sfConfig::get('sf_upload_dir') . '/' . $record->getFilename();

    if (file_exists($file))
    {
      // resize the file e.g. with sfImageTransformPlugin
      $img = new sfImage($file);
      $img
        ->resize(100, 100)
        ->save();
    }
  }
}

这将在创建没有表单的记录时起作用,例如使用夹具时。

选项 3:

使用admin.save_object 事件。

public static function listenToAdminSaveObject(sfEvent $event)
{
  $record = $event['object'];

  if ($event['object'] instanceof Banner)
  {
    // use the same code as in the `postSave` example
  }
}

选项 4:

使用sfImageTransformExtraPlugin

设置和配置有点困难(而且它的代码是一团糟:),但它可以在不重新生成所有已经调整大小的图像的情况下修改图像的大小。

【讨论】:

  • 感谢您提供这么多选择,我会尽快尝试
  • 对不起,我正忙着回答
  • 没问题。你选择了哪个选项?谢谢!
【解决方案2】:

如果你可以修改对表单类的调用,你可以这样做:

$form = new BannerForm(array(), array('validated_file_class' => 'bannerRightValidatedFile');
$form2 = new BannerForm(array(), array('validated_file_class' => 'bannerTopValidatedFile');

然后以你的形式:

class BannerForm extends BaseBannerForm
{
  public function configure()
  {
    $this->widgetSchema['filename'] = new sfWidgetFormInputFileEditable(array(
      'file_src'  => $this->getObject()->getThumbURL(),
      'is_image'  => true,
      'edit_mode' => $this->getObject()->exists()
    ));

    $this->validatorSchema['filename'] = new sfValidatorFile(array(
      'path'                 => sfConfig::get('sf_upload_dir'),
      'mime_types'           => 'web_images',
      'validated_file_class' => $this->options['validated_file_class'],
      'required'             => $this->getObject()->isNew()
    ));
  }
}

编辑:

由于您是在管理 gen 中玩游戏,我认为最好的方法是使用像 @Grad van Horck 所说的 postValidator。

您的验证类依赖于一个额外的字段。使用 postvalidator,您可以访问表单内的任何字段。然后,您只需要创建一个小开关来处理每个位置/验证类的情况。

public function configure()
{
    // ...
    $this->mergePostValidator(new sfValidatorCallback(array('callback' => array($this, 'validateFile'))));
}

public function validateFile($validator, $values, $arguments)
{
    $default = array(
        'path'       => sfConfig::get('sf_upload_dir'),
        'mime_types' => 'web_images',
        'required'   => $this->getObject()->isNew()
    );

    switch ($values['position'] ) {
        case 'right':
            $validator =  new sfValidatorFile($default + array(
                'validated_file_class' => 'bannerRightValidatedFile',
            ));
            break;

        case 'top':
            $validator =  new sfValidatorFile($default + array(
                'validated_file_class' => 'bannerTopValidatedFile',
            ));

        default:
            # code...
            break;
    }

    $values['filename'] = $validator->clean($values['filename']);

    return $values;
}

【讨论】:

  • 嗯...我明白了,但我在管理区域使用它,所以我应该更改一些部分文件,创建处理请求的操作,查看一些字段,然后创建适当的表单。也许有简单的方法?我的意思是万一管理表单
  • 嗯,我明白了,在没有修改太多文件的情况下,admin gen 内部更复杂。我认为 postValidator 是一个很好的解决方案,我会更新我的答案。
【解决方案3】:

您可以添加一个 sfCallbackValidator 作为后验证器,并相应地设置属性。

伪代码(我手头没有确切的函数签名)。

public function configure() {
  // ...
  $this->mergePostValidator(new sfCallbackValidator(array('callback' => array($this, 'validateFile'))));
}

public function validateFile($values) {
   $realValidator = new sfValidatorFile(...);
   return $realValidator->clean($values['field']);
}

【讨论】:

    猜你喜欢
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 2012-04-28
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多