2

I want to create a custom form validator to check if my user is sending a youtube url. I've already created my lib/validator/youtubeValidator.class.php

Then I use it in my MyForm.class.php : new YoutubeValidator(........)

Here is the code :

class YoutubeValidator extends sfValidatorUrl
{
  protected function configure($options = array(), $messages = array())
  {
    $this->addMessage('invalid', 'Veuillez entrer un lien Youtube');
  }
  protected function doClean($url)
  {
    $pattern = 
      '%^# 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'
      ;

    $result = preg_match($pattern, $url, $matches);
    if (false !== $result)
    {
      return $matches[1];
    }
    return false;

    if (false !== $result)
    {
      throw new sfValidatorError($this, 'invalid', array('value' => $value));
    }
    else
    {
      return true;
    }
  }
}

But it does not work at all.

Moreover, it could be great if my validator could check if youtube video does exist.

j0k
  • 22,600
  • 28
  • 79
  • 90
fallais
  • 577
  • 1
  • 8
  • 32
  • The problem is that `doClean` (the function name is explicit) should return the given value *cleaned*. So you don't have to return `true` or `false` but return the `$url` or throw a new exception if it's not valid (as @Vlad Jula-Nedelcu says). By the way, do not forget to call `parent::configure($options, $messages);` in your configure method. – j0k Oct 02 '12 at 07:40
  • Thanks j0k, concerning the options and the messages, may I set invalid and required inside my validator or in my form actions ? – fallais Oct 02 '12 at 09:12
  • required inside your form and the message inside your validator. – j0k Oct 02 '12 at 09:57

1 Answers1

1

You probably need to change the last lines to something like this:

$result = preg_match($pattern, $url, $matches);
if (false === $result)
{
   throw new sfValidatorError($this, 'invalid', array('value' => $url));
}

return $url;

This will only check if the url submitted by user is a youtube url (if it matches your regular expression). If no, will throw an exception.


UPDATE -- deleted--


UPDATE 2

class YoutubeValidator extends sfValidatorUrl
{
  protected function configure($options = array(), $messages = array())
  {
    parent::configure($options, $messages);

    $this->setMessage('invalid', 'Veuillez entrer un lien Youtube');
  }

  protected function doClean($value)
  {
    $pattern = "/(http(s)?:\/\/)?(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/";

    preg_match($pattern, $value, $matches);

    if (empty($matches[3]))
    {
      throw new sfValidatorError($this, 'invalid', array('value' => $value));
    }

    return $matches[3];
  }
}

I've tested it and seems to be working ok (returning the actual video id when using $form->getValues()).

Vlad Jula-Nedelcu
  • 1,681
  • 11
  • 17
  • I'll test it soon, but I'm not sure it will work as the code looks the same. What about my options and messages, did I make it right ? – fallais Oct 02 '12 at 06:38
  • A validator always raises an sfValidatorError exception when a value is not valid. See `doClean` method in symfony's `sfValidatorBase`: `* @param mixed $value The input value/* @return mixed The cleaned value / * @throws sfValidatorError`. Which means that when valid, the validator should returned the url (in your case) and, if not valid, throw a sfValidatorError – Vlad Jula-Nedelcu Oct 02 '12 at 08:53
  • Does this mean that the returned value will be `XXXXXXXXX` instead of `http://www.youtube.com/watch?v=XXXXXXXXXX` ? – fallais Oct 02 '12 at 09:09
  • @VladJula-Nedelcu and how do you handle Youtube link like this: `http://youtu.be/2YJk_D3GD_A` ? – j0k Oct 02 '12 at 10:58
  • 1
    @VladJula-Nedelcu the problem isn't to add a new condition, the problem is that you will have tons of condition to handle all youtube case, like: `http://www.youtube.com/v/2YJk_D3GD_A?version=3&hl=en_US`, `http://www.youtube.com/embed/2YJk_D3GD_A`, `http://youtu.be/2YJk_D3GD_A?hd=1` etc .. – j0k Oct 02 '12 at 11:36
  • ok.. i gotta admit i had no idea about all the special cases. Updated, again. – Vlad Jula-Nedelcu Oct 02 '12 at 11:59
  • @VladJula-Nedelcu so finally you're back to the OP solution with a regex, which is already defined in the `$pattern` variable. So no needs to use a different one since this one is already [*approved*](http://stackoverflow.com/a/6556662/569101). – j0k Oct 02 '12 at 12:03
  • Thanks to both of you. j0k, one question, as you've followed all my questions, if my validator returns a cleared value, I don't have to upadate value in form action anymore ? – fallais Oct 02 '12 at 12:44
  • Seems like Vlad aswered my question in his last post.. Did not you ? – fallais Oct 02 '12 at 12:46
  • Elwyn: The returned cleaned value is the video id, not the url. So $form->getValues() in your action will return an array containing the video id. As for your second request, check if the video exists, you may want to check this link: https://groups.google.com/forum/?fromgroups=#!topic/youtube-api-gdata/8KWw3JDWIT4. @j0k: Elwyn asked for a working symfony validator for youtube videos. Not for a regex expression to match the video id. You can find a lot of expressions for that with a simple google search. – Vlad Jula-Nedelcu Oct 02 '12 at 13:42
  • @Elwyn yep, you can remove it from the action then. – j0k Oct 02 '12 at 13:46
  • @VladJula-Nedelcu yep but following past questions, you will see that he already has this regex. – j0k Oct 02 '12 at 13:46
  • OK, that works very well ! Except the invalid part.. It displays "Invalid." instead of my custom message. – fallais Oct 02 '12 at 18:11
  • Use `$this->setMessage()` instead of `$this->addMessage()` – Vlad Jula-Nedelcu Oct 02 '12 at 21:09