0

In my model, a Song is linked to a Type. A Type can be Youtube, Soundcloud, Deezer, etc..

When the link value has been validated by my validator, I want to set the style_id value with the correct Type.

What is the best way to do it ?

fallais
  • 577
  • 1
  • 8
  • 32
  • I'll answer the same answer as your other question: http://stackoverflow.com/a/12669788/569101 – j0k Oct 25 '12 at 14:37
  • Maybe, I haven't been clear with my question. The problem is that I choosed the validator method, so how can I set a value of another table while processing the validator ? :S – fallais Oct 25 '12 at 14:53
  • The validator shouldn't update value in your database. The validator check if this field is ok, then return true or the field isn't ok throw an exception. That's all. If the validator pass, it means your url is ok. Then, you should update your `style_id` when you save the form. That's what I did before the youtube validation in the other answer. Instead of youtube validation, you should use a function to define the provider and then set the `style_id`. You see? – j0k Oct 25 '12 at 14:57
  • You advice me to stop using validator but the first method you explained to me ? Validators are a good way because it easy to inform the user when errors occur – fallais Oct 25 '12 at 15:01
  • No no no ! Keep the validator. It's the way to do it. Just re-use the way I started to show you, to achive the link between Song & Type. – j0k Oct 25 '12 at 15:03
  • Thank you. I've done my new validator, may I answer my question to discuss about the next step : link song to its type ? – fallais Oct 25 '12 at 15:23
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/18592/discussion-between-j0k-and-elwyn) – j0k Oct 25 '12 at 15:44
  • Good afternoon, may I ask you if you could have token a look at my problem ? – fallais Nov 05 '12 at 13:32
  • Didn't take time sorry, I'll check to night – j0k Nov 05 '12 at 13:59

1 Answers1

1

I think the best way is to perform the check twice:

  • first time: using the validator, so you know it's one of these video provider and then return the video link (not the id)
  • second time: redefine the setLink() so it takes the link, extract the id and save both the link and the style_id

How to do that.

Create a custom lib, like lib/videoProvider.class.php. This is kind of prototyped class to valid & retrieve id from a video provider. It, of course, needs improvements.

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';
    }
  }
}

Then in the doClean of your validator, you just need to call this class, like that:

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

return $url;

Finally, the setLink in Song.class.php should now be:

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

This is a first draft that must be tested and improved (test if getId() returns an id and not false, same for getProvider, etc ...)

j0k
  • 22,600
  • 28
  • 79
  • 90
  • First update. Then I have two questions : In the last code, why do you check if the value is a HTTP link while the validator does it. The getId and getProvider will quite be the same function as check functions except that they will return a string, code replication no ? – fallais Nov 06 '12 at 14:32
  • 1
    About the `setLink`, because you will have to use it to set the id directly when, for example, you edit it from your backend. Yep, this code may be refactored, as I said, it's a draft I just wrote from scratch :) – j0k Nov 06 '12 at 14:36
  • The code is updated. I have an error : You must specify the value to findOneBy. I'm understanding that getProvider() does not return anything. Moreover, is **findOneBy** case sensitive ? – fallais Nov 06 '12 at 18:11
  • The `findOneByName` in Song class is to fetch a Type by its name, if Type doesn't have a `name` field you should update the findOneBy with the correct value. Edit again my answer with your change (the previous one was rejected). – j0k Nov 06 '12 at 20:29
  • I can't check before this evening. But the error I had yesterday evening was : You must specify the value to findOneBy. Moreover, I have to create the Regex for Deezer and Soundcloud, do you know a good "regex assistant" ? Because I'm really bad at creating Regex – fallais Nov 07 '12 at 10:56
  • Ok I already reply for this error. About regex, I don't know any assistant but you will find online sandbox links at the botton of the tag: http://stackoverflow.com/tags/regex/info – j0k Nov 07 '12 at 10:57
  • My **Type** table has a **Name** field but I still have this error. Maybe getProvider does not return any value ? – fallais Nov 07 '12 at 11:06
  • Three remarks. 1 : The link (video_id) is not inserted in my database. 2 : Tell me if I'm wrong but there is a contradiction between Regex and `setLink()` because http is optional in the Regex. 3 : I've discovered that my "unique validator" on `link` filed does not work while he was working before. – fallais Nov 09 '12 at 17:38
  • 1. check sql queries or put some var_dump to see what could be wrong 2. I perform the check on http to be sure `$value` wasn't an id but an url 3. I've update the answer – j0k Nov 10 '12 at 11:57
  • 1. I'll check it this evening. 2. According to the Regex, an user can add a link without http prefix. 3. Did you update the answer according to my "unique-validator" problem ? Thanks. – fallais Nov 12 '12 at 08:10
  • I've update my answer so that your validator will work again. – j0k Nov 12 '12 at 08:18
  • May I ask you where did the problem come plz ? – fallais Nov 13 '12 at 09:30
  • 1
    check* function didn't return true/false (but an integer) and the validator checked if the return where false (a boolean). – j0k Nov 13 '12 at 09:32
  • I've tested but it does not work, I have this error : `SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '' for key 'link'.` I've put an exception in my getId(), it works well, I get the right video id. – fallais Nov 15 '12 at 18:07
  • Thank you very much. This issue is fixed, but the unique-validator does not work, strange because I updated the code when you found the issue. – fallais Nov 15 '12 at 19:26
  • Dig into the problem, put some `var_dump` to check variable, what function returns etc ... – j0k Nov 15 '12 at 19:36
  • Sure, of course. I thought it was a `return false` missing in `isValid()` but it is not. Shall we talk in chat ? – fallais Nov 15 '12 at 19:42
  • Nop, don't have time. I've update the answer so that isValid return false if none of check function works. I don't know if it will help you in debugging. – j0k Nov 15 '12 at 19:44
  • I tested it, this does not solved my problem. `isValid()` seems to be working (I put Exceptions everywhere). Then, I remember that I did not changed the code of my `addSongForm()`. Maybe, it does not appreciate the overwriting of `setLink()`. – fallais Nov 15 '12 at 19:59
  • I've changed the way to get the video's id. What do you think about it before I apply it to the rest of the code ? The updated code is in the check* function. I think Regex are not useful for this case. Moreover, I have not been able to find the problem for the validator. – fallais Nov 19 '12 at 10:44
  • I will change my answer to a wiki post, so you won't have to suggest an edit. By the way, I think the regex is still pertinent for youtube (at least). – j0k Nov 20 '12 at 08:12
  • I'm sorry @j0k but I don't understand what a wiki post is. Actually, two things remain : Finish Regex (I deal with it, I'll just ask you if I'm right but it has nothing to do with answer's validation). The second one is the `unique-validator` that does not work. – fallais Nov 20 '12 at 11:25
  • Debug, debug, debug, I can't really say more. A [community wiki post](http://meta.stackexchange.com/q/11740/182741) can be edited by lower rep: 100. I just see that you're still below .. err. – j0k Nov 20 '12 at 13:36
  • Maybe a homemade validator deactivates a `sfValidatorDoctrineUnique()`. – fallais Nov 20 '12 at 18:16
  • I have an idea. What if the validator compares `http://www.youtube.com/whatch.php?v=XXXYXYXYXYX` and `XXXYXYXYXYX`. Then, there is no problem, but the inserted value is a cleaned value. – fallais Nov 22 '12 at 14:21
  • Theorically, the validator should use the full url and the inserted value should be cleanup only in `setLink` function – j0k Nov 22 '12 at 14:49
  • So that is the reason why there is a bug. The validator compares a full URL to a video id, no ? – fallais Nov 26 '12 at 15:24
  • Maybe I don't know, you should test it to know – j0k Nov 26 '12 at 15:45
  • Shall we http://chat.stackoverflow.com/rooms/18592/discussion-between-j0k-and-elwyn plz ? – fallais Nov 26 '12 at 15:49