【问题标题】:Set a field after processing validator on an other field在另一个字段上处理验证器后设置一个字段
【发布时间】:2012-10-25 12:01:21
【问题描述】:

在我的模型中,歌曲类型相关联。类型可以是 Youtube、Soundcloud、Deezer 等。

当我的验证器验证了link 值时,我想将 style_id 值设置为正确的类型。

最好的方法是什么?

【问题讨论】:

  • 我会回答和你其他问题一样的答案:stackoverflow.com/a/12669788/569101
  • 也许,我的问题并不清楚。问题是我选择了验证器方法,那么在处理验证器时如何设置另一个表的值? :S
  • 验证器不应更新数据库中的值。验证器检查该字段是否正常,然后返回 true 或该字段不正常抛出异常。就这样。如果验证器通过,则表示您的 url 正常。然后,您应该在保存表单时更新您的style_id。这就是我在另一个答案中的 youtube 验证之前所做的。而不是 youtube 验证,您应该使用一个函数来定义提供程序,然后设置 style_id。看到了吗?
  • 您建议我停止使用验证器,但您向我解释的第一种方法?验证器是一种好方法,因为它可以在发生错误时轻松通知用户
  • 不不不!保留验证器。这是做到这一点的方法。只需重新使用我开始向您展示的方式,即可实现歌曲和类型之间的链接。

标签: php symfony-1.4 validation


【解决方案1】:

我认为最好的方法是检查两次:

  • 第一次:使用验证器,因此您知道它是这些视频提供商之一,然后返回视频链接(不是 id)
  • 第二次:重新定义setLink(),使其获取链接,提取ID并保存linkstyle_id

如何做到这一点。

创建一个自定义库,例如 lib/videoProvider.class.php。这是一种原型类,用于从视频提供商验证和检索 id。当然,它需要改进。

class videoProvider
{
  private $url;
  private $providers = array('youtube','deezer','soundcloud');
  private $youtubePattern = '%^# Match any youtube URL
      (?:https?://)?  # Optional scheme. Either http or https
      (?:www\.)?      # Optional www subdomain
      (?:             # Group host alternatives
        youtu\.be/    # Either youtu.be,
      | youtube\.com  # or youtube.com
        (?:           # Group path alternatives
          /embed/     # Either /embed/
        | /v/         # or /v/
        | /watch\?v=  # or /watch\?v=
        )             # End path alternatives.
      )               # End host alternatives.
      ([\w-]{10,12})  # Allow 10-12 for 11 char youtube id.
      $%x';
  private $deezerPattern = '/\d+/';
  private $soundcloudPattern = '[\w-]+/[\w-]+$';

  public function __construct($url)
  {
    $this->url = $url;
  }

  /**
   * @return true / false
   */
  private function checkYoutube()
  {
    return preg_match($this->youtubePattern, $this->url) ? true : false;
  }

  /**
   * @return true / false
   */
  private function checkDeezer()
  {
     // A Deezer URL has this format : http://www.deezer.com/track/61340079

     return preg_match($this->deezerPattern, $this->url) ? true : false;
  }

  /**
   * @return true / false
   */
  private function checkSoundcloud()
  {
     // A Soundcloud URL has this format : http://soundcloud.com/[A-Z Artist]/[A-Z Title]

     return preg_match($this->soundcloudPattern, $this->url) ? true : false;
  }

  /**
   * @return true / false
   */
  public function isValid()
  {
    // check all video provider as you do in your validator
    // so it will return true if it find one, otherwise false

    foreach ($this->providers as $provider)
    {
      $function = 'check'.ucfirst($provider);

      if (true === $this->$function())
      {
        return true;
      }
    }

    return false;
  }

  /**
   * @return string
   */
  public function getId()
  {
    if ($this->checkYoutube() && preg_match($this->youtubePattern, $this->url, $matches))
    {
      return $matches[1];
    }

    if ($this->checkDeezer() && preg_match($this->deezerPattern, $this->url, $matches))
    {
      return $matches[1];
    }

    if ($this->checkSoundcloud() && preg_match($this->deezerPattern, $this->url, $matches))
    {
      return $matches[1];
    }
  }

  /**
   * @return string
   */
  public function getProvider()
  {
    if ($this->checkYoutube())
    {
      return 'youtube';
    }

    if ($this->checkDeezer())
    {
      return 'deezer';
    }

    if ($this->checkSoundcloud())
    {
      return 'soundcloud';
    }
  }
}

然后在你的验证器的doClean 中,你只需要调用这个类,就像这样:

$videoProvider = new videoProvider($url);
if (false === $videoProvider->isValid())
{
  throw new sfValidatorError($this, 'invalid', array('value' => $url));
}

return $url;

最后,Song.class.php 中的setLink 现在应该是:

public function setLink($value)
{
  // only perform this tweak if the value is a http link
  if (preg_match('/^http/i', $value))
  {
    $videoProvider = new videoProvider($value);

    // define url id
    parent::_set('link', $videoProvider->getId());

    // define type id
    $provider = $videoProvider->getProvider();
    $type     = Doctrine_Core::getTable('Type')->findOneByName($provider);

    parent::_set('type_id', $type->getId());
  }
}

这是必须测试和改进的初稿(测试 getId() 是否返回 id 而不是 false,对于 getProvider 等也是如此......)

【讨论】:

  • 看起来很完美!我今晚会测试它。非常感谢。
  • 第一次更新。然后我有两个问题:在最后一个代码中,为什么在验证器执行此操作时检查该值是否为 HTTP 链接。 getId 和 getProvider 将与检查函数完全相同,只是它们将返回一个字符串,代码复制没有?
  • 关于setLink,因为当您从后端编辑它时,您必须使用它直接设置id。是的,这段代码可能会被重构,就像我说的,这是我从头开始写的草稿:)
  • 代码已更新。我有一个错误:您必须指定 findOneBy 的值。我了解 getProvider() 不返回任何内容。此外,findOneBy 是否区分大小写?
  • check* 函数没有返回真/假(而是一个整数),验证器检查是否返回假(布尔值)。
猜你喜欢
  • 2020-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 2022-07-20
  • 1970-01-01
相关资源
最近更新 更多