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

編集:

admin gen内でプレイしているので、@ GradvanHorckが言うように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 に答える