0

I want to convert a value before saving the form. I don't know where to add the code because the only method is form->save()

Could you please help me ?

Edit:

  if ($this->form->isValid())
  {
    $url = $this->form->getObject()->getLink();
    parse_str(parse_url($url, PHP_URL_QUERY), $my_array_of_vars);
    $this->form->getObject()->setLink($my_array_of_vars['v']); 

    $song = $this->form->save();

    $this->getUser()->setFlash('notice', 'Thank you, the song has been added');

    $this->redirect('@homepage');
  }
j0k
  • 22,600
  • 28
  • 79
  • 90
fallais
  • 577
  • 1
  • 8
  • 32

3 Answers3

3

The @pankar answer is almost good. But the $this->form->save() will override the setLink.

First of all, define the function to retrieve the youtube id, as defined here in a new tools class: lib/myTools.class.php

<?php

class myTools
{
  /**
   * Get youtube video ID from URL
   *
   * @see https://stackoverflow.com/a/6556662/569101
   * @param string $url
   * @return string Youtube video id or FALSE if none found. 
   */
  public static function youtube_id_from_url($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;
  }
}

Then, update your action with this:

if ($this->form->isValid())
{
  // save the form
  $song = $this->form->save();

  // update saved value
  $youtube_id = myTools::youtube_id_from_url($song->getLink());
  $song->setLink($youtube_id);
  $song->save();

  $this->getUser()->setFlash('notice', 'Thank you, the song has been added');

  $this->redirect('@homepage');
}

By the way, this method is ok if you use your form in only one place. Since the update is perform in the action and not in the form class. Otherwise, as @glerendegui said, you will have to do this action in the form class. But I will rather do it in the doUpdateObject instead of doSave. Since the code says:

  /**
   * Updates the values of the object with the cleaned up values.
   *
   * If you want to add some logic before updating or update other associated
   * objects, this is the method to override.
   *
   * @param array $values An array of values
   */
  abstract protected function doUpdateObject($values);

So I will do it in this way, inside your form (lib/form/doctrine/yourForm.class.php):

class yourForm extends BaseYourForm
{
  public function configure()
  {
  }

  protected function doUpdateObject($values)
  {
    $youtube_id = myTools::youtube_id_from_url($values['link']);
    $this->getObject()->setLink($youtube_id);

    return parent::doUpdateObject($values);
  }
}
Community
  • 1
  • 1
j0k
  • 22,600
  • 28
  • 79
  • 90
  • Since on success the user is redirect to `@homepage` it makes no difference if the `setLink` method is overriden by the computed value. After all the desired input for this field is the computed value rather than the one submitted! You have a point though if the form was presented again to the user. – pankar Oct 01 '12 at 08:50
  • +1 for getting into trouble to present a complete answer capturing the need of a centralized/generalized method to extract youtube videoIds – pankar Oct 01 '12 at 08:51
  • Thank, I'll test it very soon. I should create a custom validator in order to check if my link is a youtube link, shouldn't I ? – fallais Oct 01 '12 at 09:20
0

In your execute* action after binding the form:

EDITED AFTER OP's input

  if ($this->form->isValid())
  {
    $url = $this->form->getObject()->getLink(); // get the url

    $videoId=parse_url($url, PHP_URL_QUERY); // extract the videoid portion

    $this->form->getObject()->setLink($videoId); // update object with the new value

    $song = $this->form->save(); // save the object

    $this->getUser()->setFlash('notice', 'Thank you, the song has been added');

    $this->redirect('@homepage');
  }
j0k
  • 22,600
  • 28
  • 79
  • 90
pankar
  • 1,623
  • 1
  • 11
  • 21
  • That is perfect, I found many topics that explain how to override the save method. I prefer that solution. – fallais Sep 28 '12 at 13:09
  • I tested but it does not work. I edit my post to show you my code. – fallais Sep 28 '12 at 16:45
  • I got this Unknown record property / related component "value" on "Song" – fallais Sep 28 '12 at 17:04
  • ehm...The `getValue()`/`setValue()` was just an example. You should use the name of the required field from your model, i.e if the field is named `url` the you should use `getUrl()` and `setUrl()`. Hope this makes sense – pankar Sep 28 '12 at 17:09
  • Ooh.. I'm sorry, I didn't get it like that. I tried to add my field in parameter : getValue('link'). But it still does not work. My code updated. – fallais Sep 28 '12 at 17:18
  • The full link is still inserted in my base but not the video id. – fallais Sep 28 '12 at 17:26
  • What exactly are you trying to achieve?What is the input of processing and what is the desired output?..Base..video id...I lost you... – pankar Sep 28 '12 at 19:20
  • The input is a url of a youtube video, the output is the youtube video id only. – fallais Sep 28 '12 at 19:31
  • I've updated my answer based on your input. See if this fits your needs – pankar Sep 28 '12 at 19:40
  • Hello, it still does not work. The full link is inserted into database. – fallais Oct 01 '12 at 06:37
0

You should add this behavior inside the form itself, and not in the action (that's the idea about symfony forms). So, override the doSave($con = null) of the form, something like:

class yourForm extends whateverForm {

 public function configure() { ... }
 public function doSave($con = null) {
   // process form values
   return parent::doSave();
 }
}
j0k
  • 22,600
  • 28
  • 79
  • 90
glerendegui
  • 1,457
  • 13
  • 15
  • If I choose this method, where do I have to write this code ? Is that best practice compared to the other solution ? – fallais Oct 01 '12 at 06:38
  • This it's your form class code. By example, in your action, if you do: $this->form = new xxxForm(...), then, edit xxxForm.class (probably in lib/form/doctrine/xxxForm.class.php). The only thing you should to add is the doSave() part. – glerendegui Oct 01 '12 at 18:10
  • About if it is the best practice, it depends on what you want to do. Symfony forms theory says that forms should be action-independent, so this way they can be used any time at everywhere of your code (even other projects too, in action custom code or generated modules). That's the idea about code reuse. If this value change that you whan to do is part of the form, then should be part of his behavoiur. Think about using your in some generated module. – glerendegui Oct 01 '12 at 18:10