0

In my application I have a lot of modules and a lot of forms with their own widgets.
I have been trying to Globally 'unset', 'hide' or 'make read only' a widget.
I know that its possible to do it for one widget in the configure() function of the form, but I am looking for a better solution, if possible in a global way. It could be a pain to change all module forms and keep track of them.
The thread could be a bit long but I think that its easy to understand the problem. Thank you so much if you have time to read it :)

I have built a simple news module with the Timestampable behavior to test some options but still none of them worked.

  • table: TbNews
  • columns:
    • id as primary key
    • scontent as a text field for saving the news content.
    • created_at as date time. (Timestampable behavior)
    • updated_at as date time. (Timestampable behavior)


TbNews schema.yml:

TbNews:
  connection: doctrine_master
  tableName: tb_news
  columns:
    id:
      type: integer(8)
      fixed: false
      unsigned: false
      primary: true
      autoincrement: true
    scontent:
      type: string(64000)
      fixed: false
      unsigned: false
      primary: false
      notnull: true
      autoincrement: false
  actAs:
    Timestampable:
      created:
        name: created_at
        type: timestamp
        format: Y-m-d H:i:s
        options:
          notnull: false
          required: false
      updated:
        name: updated_at
        type: timestamp
        format: Y-m-d H:i:s
        options:
          notnull: false
          required: false


TbNews updated_at in Form
(for the example, only wrote here the updated_at column):

class TbNewsForm extends PluginTbNewsForm
{
  public function configure()
  {
      $this->setWidgets(array(
          'updated_at'   => new sfWidgetFormDateTime(),
      ));
      $this->setValidators(array(
        'updated_at'   => new sfValidatorDateTime(array('required' => false)),
      ));
  }
}


Template _form.php for TbNews updated_at:
Tested a lot of options, manually rendering updated_at with: "echo $form['updated_at']" and without rendering it.

<?php echo $form->renderHiddenFields(false) ?>


Global tests with update_at column in: lib/form/doctrine/BaseFormDoctrine.class.php:

  • With sfWidgetFormInputHidden(), widget is not rendered in template.
    Tested unsetting it, without unsetting it, with setWidget, without it... all possible options but the field updated_at is not rendered in template. ( used renderHiddenFields() )
abstract class BaseFormDoctrine extends sfFormDoctrine
{
  public function setup()
  {
      $value_updated_at = $this->getObject()->updated_at;
      unset($this->widgetSchema['updated_at']);
      unset($this->validatorSchema['updated_at']);
      $this->widgetSchema['updated_at'] = new sfWidgetFormInputHidden();
      $this->widgetSchema['updated_at']->setOption('is_hidden', 'true');
      $this->widgetSchema['updated_at']->setOption('type', 'hidden'); 
      $this->setDefault('updated_at', $value_updated_at);
      $this->setWidget('updated_at', new sfWidgetFormInputHidden(array('value'=>$value_updated_at)));
      //$this->setWidget('updated_at', $this->widgetSchema['updated_at']);
  }
}


  • With read only:
    Added the field updated_at in the _form.php template, but its not shown as read only. Seems doesnt work with sfWidgetFormDateTime.
      $this->widgetSchema['updated_at']->setAttribute('readonly', 'readonly');
    


Questions and thoughts:
Probably BaseFormDoctrine is not the right way to global change a widget in all Form modules or there is probably something wrong in my tests.

As you may probably know, if we use the above code directly in the Form widget TbNewsForm configure(), we can easily change the widget from one type to another type, and individually render or hide it, and it works.
  • But how can we implement it in a global way?
  • Should it be necessary to change core code of symfony Doctrine?

Thank you so much if you could take time to read it, any comment or solution is welcome :)

xtrm
  • 966
  • 9
  • 22
  • Basically, you want `updated_at` & `created_at` to be hidden for all your form, right? – j0k Feb 08 '13 at 09:45
  • yes j0k, but affecting all modules which has created_at and updated_at fields. – xtrm Feb 08 '13 at 09:47
  • Tested also only globally Unsetting those fields in BaseFormDoctrine, but NULL values are saved for created_at on update: UPDATE tb_news SET scontent = 'content3', created_at='', updated_at='2013-02-07 11:59:29' WHERE id='3'; Checked Listener code at C:\php5\PEAR\symfony\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Template\Listener\Timestampable.php but there is no easy solution. – xtrm Feb 08 '13 at 09:55
  • I also have a lot of form classes in my projects, and I usually unset `created_at` & `updated_at` inside the configure. I prefer to see *what's going on* in the right form class instead of globally. What if you want to see these field in a backend app? Will you re-add them in the form class? – j0k Feb 08 '13 at 09:58
  • Yes, as you said thats the best way and If there is no other option I will have to do it manually for each form class. However it we find a working way to set it globally, it would be easy to add a module black/whitelist condition in the BaseFormDoctrine so that we know what modules form widgets are being filtered, filtering only some of them and only when we are not in backend. – xtrm Feb 08 '13 at 10:30
  • @xtm You can do it in the base form, but why do you need this? You should use `$this->useFields()` in the `configure` method and just leave unneeded fields out. – 1ed Feb 08 '13 at 23:01

2 Answers2

0

Changing the BaseFormDoctrine class won't help you. The widgets for a form are set in the base class of the given form (BaseTbNewsForm in your case), so they will override any changes made in the BaseFormDoctrine class.

If you want to do the same operation for each form but don't want to rewrite the code in each class you can create a utility class and call it's method's in the forms' configure() function.

I don't think there is an option to do it globally without changing the Doctrine / Symfony internals (you would have to change the way in which base classes for you forms are generated).

Michal Trojanowski
  • 10,641
  • 2
  • 22
  • 41
  • Thank you Michal, your comment is really appretiated and its somehow what I thought. I will try some minor changes at the core and report them back soon, ty :) – xtrm Feb 08 '13 at 11:00
0

I have found a way which works, hovewer maybe not be the best solution since it involves modifing the source code of symfony. The function: setupInheritance() in the core file: sfFormDoctrine.class.php is called by all forms after setting widgets and validators, if we add the code there, our changes will work globally for all forms.
In the example below, all widgets 'created_at' and 'updated_at' will be unset, and then set to be hidden:

 /**
   * Used in generated forms when models use inheritance.
   */
  protected function setupInheritance()
  {
    if (isset($this))
    {
      $oWidgetSchema = $this->getWidgetSchema();
      if (isset($oWidgetSchema))
      {
        $screatedcolumn = "created_at";
        $supdatedcolumn = "updated_at";

        //if ($this->isNew()) //we can add a check for new records

        //we can also add checks for frontend or backend
        //$request = sfContext::getInstance()->getRequest();
        //$this->url = 'http'.($request->isSecure() ? 's' : '').'://'. $request->getHost();
        //$suri_params = $request->getParameterHolder()->getAll();

        //set [created_at] as hidden field widget, and set its default value to the Original one before sending it to Timestampable.php Listener.
        if ( $oWidgetSchema->offsetExists($screatedcolumn) )
        {
          $value_created_at = $this->getObject()->created_at;
          unset($this->widgetSchema[$screatedcolumn]);
          $this->widgetSchema[$screatedcolumn] = new sfWidgetFormInputHidden();
          $this->widgetSchema[$screatedcolumn]->setOption('is_hidden', 'true');
          $this->widgetSchema[$screatedcolumn]->setOption('type', 'hidden');
          //unset($this->validatorSchema[$screatedcolumn]); //unset its validator to make sure values are not checked by default, optional.
          $this->setDefault($screatedcolumn, $value_created_at);
        }
        //set [updated_at] as hidden field widget, and set its default value to time() before sending it to Timestampable.php Listener.
        if ( $oWidgetSchema->offsetExists($supdatedcolumn) )
        {
          //$value_updated_at = $this->getObject()->updated_at;
          unset($this->widgetSchema[$supdatedcolumn]);
          $this->widgetSchema[$supdatedcolumn] = new sfWidgetFormInputHidden();
          $this->widgetSchema[$supdatedcolumn]->setOption('is_hidden', 'true');
          $this->widgetSchema[$supdatedcolumn]->setOption('type', 'hidden');
          //unset($this->validatorSchema[$supdatedcolumn]); //unset its validator to make sure values are not checked by default, optional.
          $this->setDefault($supdatedcolumn, time());
        }
      }
    }
xtrm
  • 966
  • 9
  • 22