phpsymfony1symfony-formssymfony-1.4

Not-exists filter for m-n relation in symfony 1.4


I have a many-to-many relation in symfony 1.4. I am using the Doctrine admin generator, and would like to add an "Is Empty" checkbox to the standard sfWidgetFormDoctrineChoice for that field, to do a "WHERE NOT EXISTS" query and find untagged entries. Anyone seen a solution for this?

Thank you!


Solution

  • widget:

    class ynWidgetFormDoctrineChoiceEmpty extends sfWidgetFormDoctrineChoice
    {
      protected function configure( $options = array(), $attributes = array() )
      {
        parent::configure( $options, $attributes );
    
        $this->addOption( 'with_empty', false );
        $this->addOption( 'empty_label', 'none' );
        $this->addOption( 'template', '%select%<div>%empty_checkbox% %empty_label%</div>' );
      }
    
      public function render( $name, $value = null, $attributes = array(), $errors = array() )
      {
        $select = parent::render( $name, $value, $attributes, $errors );
    
        if ( $this->getOption('with_empty') ) {
          $values = array_merge(array('text' => '', 'is_empty' => false), is_array($value) ? $value : array());
    
          return strtr($this->getOption('template'), array(
            '%select%'         => $select,
            '%empty_checkbox%' => $this->renderTag('input', array('type' => 'checkbox', 'name' => $name.'[is_empty]', 'checked' => $values['is_empty'] ? 'checked' : '')),
            '%empty_label%'    => $this->renderContentTag('label', $this->translate($this->getOption('empty_label')), array('for' => $this->generateId($name.'[is_empty]'))),
          ));
        }
        else {
          return $select;
        }
      }
    }
    

    validator:

    class ynValidatorDoctrineChoiceEmpty extends sfValidatorDoctrineChoice
    {
      public function configure( $options = array(), $messages = array() )
      {
        parent::configure( $options = array(), $messages = array() );
    
        $this->addMessage('empty_or_not', 'Select either choices or none');
      }
    
      protected function doClean( $values )
      {
        if (
          isset( $values['is_empty'] )
          && $values['is_empty'] == 'on'
        ) {
          if ( count( $values ) > 1 ) {
            // 'empty' selected alongside subjects
            throw new sfValidatorError( $this, 'empty_or_not' );
          }
    
          return $values;
        }
        else {
          return parent::doClean( $values );
        }
      }
    }
    

    in FooFormFilter:

    public function addBarListColumnQuery( Doctrine_Query $query, $field, $values )
    {
      if (!is_array($values))
      {
        $values = array($values);
      }
    
      if (!count($values))
      {
        return;
      }
    
      if (
        isset( $values['is_empty'] )
        && $values['is_empty'] == 'on'
      ) {
        $query
          ->andWhere('NOT EXISTS (SELECT fb.bar_id '
            . 'FROM FooBar fb where ' . $query->getRootAlias()
            . '.id=fb.foo_id)');
      }
      else {
        $query
          ->leftJoin($query->getRootAlias().'.FooBar FooBar')
          ->andWhereIn('FooBar.bar_id', $values)
        ;
      }
    }