0

我有这个模型:

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 类。我怎样才能做到这一点?

4

3 回答 3

2

我可以推荐 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

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

于 2013-03-11T20:50:43.077 回答
1

您可以添加一个 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']);
}
于 2013-03-11T15:52:40.393 回答
1

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

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

编辑:

由于您是在管理员内部玩,我认为最好的方法是使用像@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;
}
于 2013-03-11T15:55:19.277 回答