Dec 11 2008

Symfony Form: записываем относительный путь для файлов в БД

Category: Symfonyingvar @ 19:12

Рецепт только для Symfony 1.2. На других версиях не проверялся.
При работе с формами, если требуется сохранить файлы, то в БД пишется только имя загружаемого файла, например: fa3d2c687c04e411372045106.jpg. Мне удобнее сохранить в БД относительный путь к картинке, так легче работать на выводе, например: /uploads/news/2008/10/16/fa3d2c687c04e411372045106.jpg. Для решения этой задачи требуется указать желаемый путь к директории $this->path в классе NewsForm и переназначить метод saveFile, который используется для записи имени файла в БД. Единственное, что перестанет работать удаление файлов, т.к. путь получается неверный, чтобы это исправить расширяем базовый класс BaseFormPropel и корректируем путь к файлам. Полагаю, что то же самое сработает и для Doctrine.

Листинг 1: Изменяем класс NewsForm.class.php, чтобы переназначить пути к файлам

<?php

/**
 * News form.
 */
class NewsForm extends BaseNewsForm
{
  public function configure()
  {
    parent::configure();

    $this->path = 'news/' . date('Y/m/d');

    $this->setWidget('image', new sfWidgetFormInputFileEditable(array(  
      'file_src'       => '-foo-',
      'is_image'       => true  
    )));  
  
    $this->validatorSchema['image'] = new myValidatorFile(array(  
      'required'   => false,  
      'mime_types' => 'web_images',  
      'path'       => sfConfig::get('sf_upload_dir') . $this->path,  
    ));

    $this->validatorSchema->setOption('allow_extra_fields', true);
    $this->validatorSchema->setOption('filter_extra_fields', false);
  }

  public function saveFile($field, $filename = null, sfValidatedFile $file = null)
  {
    return '/uploads/' . $this->path . '/' . parent::saveFile($field, $filename, $file);
  }
}

Листинг 2: Изменяем класс BaseFormPropel.class.php, чтобы сработало удаление файлов

<?php
abstract class BaseFormPropel extends sfFormPropel
{
  public function setup()
  {
  }

  /**
   * Removes the current file for the field.
   *
   * @param string $field The field name
   */
  protected function removeFile($field)
  {
    if (!$this->validatorSchema[$field] instanceof sfValidatorFile)
    {
      throw new LogicException(sprintf('You cannot remove the current file for field 
          "%s" as the field is not a file.', $field));
    }

    $column = call_user_func(array(constant(get_class($this->object).'::PEER'), 'translateFieldName'), 
        $field, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_PHPNAME);
    $getter = 'get'.$column;

    if (($directory = sfConfig::get('sf_web_dir')) && is_file($directory.$this->object->$getter()))
    {
      unlink($directory.$this->object->$getter());
    }
  }

}

Другие ссылки:
The symfony Forms Book: Chapter 4 — Propel Integration
SYMFONY 1.2: UPLOAD A FILE INSIDE AN EMBEDDED FORM

Tags:

6 Responses to “Symfony Form: записываем относительный путь для файлов в БД”

  1. sergey says:

    а ничего что new sfWidgetFormInputFileEditable требует обязательный параметр file_src ?
    пример не соответствует реально работающей форме

  2. ingvar says:

    Верное замечание :), спасибо, подправил.

  3. dmitry says:

    я еще новичок :)
    сделал по вашему примеру, чето как писал файлы в uploads так и пишет…и ошибок никаких не выводит..
    подскажите мож настроить чтото надо

  4. ingvar says:

    Покажите полный пример Вашего кода.

  5. masterY0da says:

    меня интересует точное расположение этих файлов, кторые редактируются, потому как в своих я правлю ,а такое чувство что они даже не выполняются :(
    /lib/form/ContentViewForm.class.php
    и
    /lib/form/baseFormpropel.class.php
    код в 1
    class ContentViewForm extends BaseContentViewForm
    {
    parent::configure();

    $this->path = ‘view/’ . date(‘Y/m/d’);

    $this->setWidget(‘file’, new sfWidgetFormInputFileEditable(array(
    ‘file_src’ => ‘-foo-‘,
    ‘is_image’ => true
    )));

    $this->validatorSchema[‘file’] = new myValidatorFile(array(
    ‘required’ => false,
    ‘mime_types’ => ‘web_images’,
    ‘path’ => sfConfig::get(‘sf_upload_dir’) . $this->path,
    ));

    $this->validatorSchema->setOption(‘allow_extra_fields’, true);
    $this->validatorSchema->setOption(‘filter_extra_fields’, false);
    }

    public function saveFile($field, $filename = null, sfValidatedFile $file = null)
    {
    return ‘/uploads/’ . $this->path . ‘/’ . parent::saveFile($field, $filename, $file);
    }

    }
    во втром

    abstract class BaseFormPropel extends sfFormPropel
    {
    public function setup()
    {
    }
    protected function removeFile($field)
    {
    if (!$this->validatorSchema[$field] instanceof sfValidatorFile)
    {
    throw new LogicException(sprintf(‘You cannot remove the current file for field
    «%s» as the field is not a file.’, $field));
    }

    $column = call_user_func(array(constant(get_class($this->object).’::PEER’), ‘translateFieldName’),
    $field, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_PHPNAME);
    $getter = ‘get’.$column;

    if (($directory = sfConfig::get(‘sf_web_dir’)) && is_file($directory.$this->object->$getter()))
    {
    unlink($directory.$this->object->$getter());
    }
    }

    }

  6. ingvar says:

    Вот такой должен быть пример. Это класс NewsForm. Этого вполне достаточно.

    class NewsForm extends BaseNewsForm
    {
    public function configure()
    {
    parent::configure();

    $this->path = ‘news/’ . date(‘Y/m/d’);

    $this->setWidget(‘file’, new sfWidgetFormInputFile(),);

    $this->validatorSchema[‘file’] = new sfValidatorFile(array(
    ‘required’ => false,
    ‘path’ => $this->path,
    ‘mime_types’ => ‘web_images’,
    ))

    $this->setWidget(‘image_url_1’, sfCpanelForm::getWidgetFormInputFileEditable());
    $this->validatorSchema[‘image_url_1’] = sfCpanelForm::getsfValidatorFile($this->path, 1024000);
    }

    public function saveFile($field, $filename = null, sfValidatedFile $file = null)
    {
    return ‘/uploads/’ . $this->path . ‘/’ . parent::saveFile($field, $filename, $file);
    }

Leave a Reply to ingvar