Question

I need to have a start and end time widget on a form.

i.e. the user selects a date and then selects the start and end time.

In the standard date widget, you can select a date and a time, however I need to be able to select a finish time too.

Have any of you done it before?

I could create 3 separate widgets:

  • Date
  • Start Time
  • End Time

When the form is saved, I'll do an update on the object to combine all values into one. For example, I'll get the date and add the start time to it and then save to the field "start_date" and then I'll get the date and add the end time to it and then save to the field "end_date". It does however seem a very long winded way to do something which should be fairly trivial for a form framework.

Is this how you'd do it? Thanks guys!

Was it helpful?

Solution

I think what you want to want achieve with symfony forms is pretty easy. You are right, you need three separate widgets and three separate validators, there isn't an out of the box solution for this exact situation.

In your form configure method you would have something like:

$this->setWidgets(array(
  'date' => new sfWidgetFormDate(),
  'time_start' => new sfWidgetFormTime(array('label' => 'Start Time', 'with_seconds' => false)),
  'time_finish' => new sfWidgetFormTime(array('label' => 'End Time', 'with_seconds' => false)
));

$this->setValidators(array(
  'date' => new sfValidatorDate(),   // by default outputs in format Y-m-d
  'time_start' => new sfValidatorTime(),  // by default outputs in format H:i:s
  'time_finish' => new sfValidatorTime(),
));

Let's assume that the object has two properties, as you suggested, both are datetime fields.

In your action you would have something like the following to set the datetime fields:

$values = $this->form->getValues();

$object->setStartDateTime(sprintf('%s %s', $values['date'], $values['time_start']));
$object->setFinishDateTime(sprintf('%s %s', $values['date'], $value['time_finish']));

Edit: another suggestion is not use the built in time widget sfWidgetFormTime as it can look pretty ugly. You can simply use a normal text box (centre aligned, with maxlength=5), and the sfValidatorTime validator will still work perfectly.

Hope that helps.

OTHER TIPS

Your requirement sounds application-specific and not really something the Symfony form framework would help you with out-of-the-box.

I would go with your suggestion of generating start_date and end_date from the output of the three widgets, or if your application needs to return date, start_time and end_time separately later, then possibly just save three values separately and manipulate them when queried.

So, I've done the code for it and it works very well. I've removed all the unnecessary widgets and validators. Here is how I did it:

class VisitForm extends BaseVisitForm
{
  private function getMinutes()
  {
     $minutes = array();

     for($i = 0; $i < 60; $i = $i + 5)
     {
       $minutes[$i] = sprintf('%02d', $i);
     }
     return $minutes;   
  }

  public function configure()
  {

      $this->setWidgets(array(
      'id'            => new sfWidgetFormInputHidden(),
      'date'            => new sfWidgetFormJQueryDate(array('date_widget' => new sfWidgetFormDate(array('years' => $years, 'can_be_empty'=> false)), 'image' => '/images/icons/calendar.png', 'format'=>'%day%/%month%/%year%')),
      'start_time'    => new sfWidgetFormTime(array('with_seconds' => false,'can_be_empty'=> false, 'default' => '08:00', 'minutes'=> array_combine($this->getMinutes(), $this->getMinutes()))),
      'end_time'          => new sfWidgetFormTime(array('with_seconds' => false,'can_be_empty'=> false, 'default' => '08:00', 'minutes'=> array_combine($this->getMinutes(), $this->getMinutes())))

    ));

    $this->setValidators(array(

      'start_time'    => new sfValidatorTime(),
      'end_time'      => new sfValidatorTime(),
      'date'            => new sfValidatorDate(),
    ));

    $this->widgetSchema->setNameFormat('visit[%s]');

    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
  }

 protected function doUpdateObject($values)
  {     
    $this->getObject()->setStartDate(sprintf("%s %s", $values['date'], $values['start_time']));
    $this->getObject()->setEndDate(sprintf("%s %s", $values['date'], $values['end_time']));

    parent::doUpdateObject($values);
  }

  public function updateDefaultsFromObject()
  {
    if(!$this->getObject()->isNew())
    {
        $this->setDefault('date', $this->getObject()->getDateTimeObject('start_date')->format('Y-m-d'));
        $this->setDefault('start_time', $this->getObject()->getDateTimeObject('start_date')->format('H:i'));
        $this->setDefault('end_time', $this->getObject()->getDateTimeObject('end_date')->format('H:i'));
    }
    parent::updateDefaultsFromObject();

  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top