Symfony1 功能测试和sfWidgetFormChoice,具有多个true

Symfony1 功能测试和sfWidgetFormChoice,具有多个true,symfony1,symfony-1.4,symfony-forms,Symfony1,Symfony 1.4,Symfony Forms,我想测试编辑表单的用户,该表单中有一个。在功能测试中,如何从该表单小部件中选择或取消选择值 表单设置: 'regions_list' => new sfWidgetFormDoctrineChoice(array( 'multiple' => true, 'model' => 'Region' )), 功能测试: $browser-> getRoute('profile')-> //setField('profile[regions_list]

我想测试编辑表单的用户,该表单中有一个
。在功能测试中,如何从该表单小部件中选择或取消选择

表单设置:

'regions_list' => new sfWidgetFormDoctrineChoice(array(
  'multiple' => true, 
  'model' => 'Region'
)),
功能测试:

$browser->
  getRoute('profile')->

  //setField('profile[regions_list]', '[9][8]')->  // tried syntaxmany combinations
  click('Save Profile', array(
    'profile' => array(
      // 'regions_list' => ???,
      // I've tried many combinations even with setField and none made sense and where testable so far
    )
  ))->

  with('form')->begin()->
    hasErrors(0)->
    hasGlobalError(0)->
  end()
;

我从来没有在
点击()
周围放置带('form')的
,这是我的测试:

$browser->
  getRoute('profile')->

  click('Save Profile', array(
    'profile' => array('regions_list' => array(8,9)
        // with: <option value="8">something</option><option value="9">else</option>
        // ... and other fields
    )
  ))->
  end()->

  with('form')->begin()->
    debug() -> // added this line so you can see what is happening
    hasErrors(0)->
    hasGlobalError(0)->
  end()
;
$browser->
getRoute('profile')->
单击('保存配置文件',数组(
'profile'=>array('regions\u list'=>array(8,9)
//有什么事吗
//…和其他领域
)
))->
结束()->
使用('form')->begin()->
debug()->//添加了这一行,以便您可以看到发生了什么
hasErrors(0)->
hasGlobalError(0)->
完()
;

好吧,在深入研究click()过程之后,我无法得到我期望的结果

解决办法如下:

标记中,我希望如果我不发布任何值,它将按原样重新发布,如果我指定了值,它将只发布这些值,而不会尝试通过值控制开/关

它现在的反应方式是将初始值和所选值合并在一起,并替换与所选值键匹配的初始值键,这对我来说没有意义,因为这些键或它们的顺序是不相关的。我只关心选择的选项值

我的问题的答案是:在当前的实现中,您无法实现您所期望的

解决方案: 覆盖(或提交补丁,如果有时间)sfBrowserBase类中的doClickElement函数,该函数可能如下所示:(查找3条注释//修复选择多个和最后2个要添加的方法)

现在:
“profile'=>array('regions\u list'=>array(8,9))适合我。

您尝试了
setField(“profile[regions\u list]”,array(8,9))
?我已经尝试过了,现在又尝试过了,但在1.4.5版本中它不起作用=(我将尝试使用最新的1.4.x从头开始进行测试,以确保如果我是唯一一个没有得到它的人,那么不会造成混乱!昨天在发布我的问题时,我确实考虑过这一点;)我正在使用的这个项目是在1.4.5上,它不起作用=(但我想我可能会尝试使用最新版本?更准确地说,我得到了一个区域列表无效,并且debug()中发布的区域列表值显示了一个数组,上面有两个值(8,9),后面是已经存在的值,因此这些值也不会被取消选择。我得到了
[无效]
当我试图添加一个不存在的
区域
id时。这不正是验证程序在做它的工作吗?是的。没错。所以试着看看[8,9]是不是确实存在于
区域
表中的id。
public function doClickElement(DOMElement $item, $arguments = array(), $options = array())
{
  $method = strtolower(isset($options['method']) ? $options['method'] : 'get');

  if ('a' == $item->nodeName)
  {
    if (in_array($method, array('post', 'put', 'delete')))
    {
      if (isset($options['_with_csrf']) && $options['_with_csrf'])
      {
        $arguments['_with_csrf'] = true;
      }

      return array($item->getAttribute('href'), $method, $arguments);
    }
    else
    {
      return array($item->getAttribute('href'), 'get', $arguments);
    }
  }
  else if ('button' == $item->nodeName || ('input' == $item->nodeName && in_array($item->getAttribute('type'), array('submit', 'button', 'image'))))
  {
    // add the item's value to the arguments
    $this->parseArgumentAsArray($item->getAttribute('name'), $item->getAttribute('value'), $arguments);

    // use the ancestor form element
    do
    {
      if (null === $item = $item->parentNode)
      {
        throw new Exception('The clicked form element does not have a form ancestor.');
      }
    }
    while ('form' != $item->nodeName);
  }

  // form attributes
  $url = $item->getAttribute('action');
  if (!$url || '#' == $url)
  {
    $url = $this->stack[$this->stackPosition]['uri'];
  }
  $method = strtolower(isset($options['method']) ? $options['method'] : ($item->getAttribute('method') ? $item->getAttribute('method') : 'get'));

  // merge form default values and arguments
  $defaults = array();
  $arguments = sfToolkit::arrayDeepMerge($this->fields, $arguments);

  // fix for select multiple
  $select_multiple_to_check = array();

  $xpath = $this->getResponseDomXpath();
  foreach ($xpath->query('descendant::input | descendant::textarea | descendant::select', $item) as $element)
  {
    if ($element->hasAttribute('disabled'))
    {
      continue;
    }

    $elementName = $element->getAttribute('name');
    $nodeName    = $element->nodeName;
    $value       = null;

    if ($nodeName == 'input' && ($element->getAttribute('type') == 'checkbox' || $element->getAttribute('type') == 'radio'))
    {
      // fix for select multiple
      if (substr($elementName, -2) == '[]') 
      {
        $select_multiple_to_check[$elementName] = true;
      }

      if ($element->getAttribute('checked'))
      {
        $value = $element->hasAttribute('value') ? $element->getAttribute('value') : '1';
      }
    }
    else if ($nodeName == 'input' && $element->getAttribute('type') == 'file')
    {
      $filename = array_key_exists($elementName, $arguments) ? $arguments[$elementName] : sfToolkit::getArrayValueForPath($arguments, $elementName, '');

      if (is_readable($filename))
      {
        $fileError = UPLOAD_ERR_OK;
        $fileSize = filesize($filename);
      }
      else
      {
        $fileError = UPLOAD_ERR_NO_FILE;
        $fileSize = 0;
      }

      unset($arguments[$elementName]);

      $this->parseArgumentAsArray($elementName, array('name' => basename($filename), 'type' => '', 'tmp_name' => $filename, 'error' => $fileError, 'size' => $fileSize), $this->files);
    }
    else if ('input' == $nodeName && !in_array($element->getAttribute('type'), array('submit', 'button', 'image')))
    {
      $value = $element->getAttribute('value');
    }
    else if ($nodeName == 'textarea')
    {
      $value = '';
      foreach ($element->childNodes as $el)
      {
        $value .= $this->getResponseDom()->saveXML($el);
      }
    }
    else if ($nodeName == 'select')
    {
      if ($multiple = $element->hasAttribute('multiple'))
      {
        // fix for select multiple
        $select_multiple_to_check[$elementName] = true;

        $elementName = str_replace('[]', '', $elementName);
        $value = array();
      }
      else
      {
        $value = null;
      }

      $found = false;
      foreach ($xpath->query('descendant::option', $element) as $option)
      {
        if ($option->getAttribute('selected'))
        {
          $found = true;
          if ($multiple)
          {
            $value[] = $option->getAttribute('value');
          }
          else
          {
            $value = $option->getAttribute('value');
          }
        }
      }
      $option = $xpath->query('descendant::option', $element)->item(0);
      if (!$found && !$multiple && $option instanceof DOMElement)
      {
        $value = $option->getAttribute('value');
      }


    }

    if (null !== $value)
    {
      $this->parseArgumentAsArray($elementName, $value, $defaults);
    }
  }

  // fix for select multiple
  foreach($select_multiple_to_check as $elementName => $uselessbool)
  {
    $path = array_filter(preg_split('/(\[ | \[\] | \])/x', $elementName), create_function('$s', 'return $s !== "";'));
    if ($this->findInArrayByArrayPath($arguments, $path) !== false)
    {
      $this->unsetInArrayByArrayPath($defaults, $path);
    }
  }

  $arguments = sfToolkit::arrayDeepMerge($defaults, $arguments);

  if (in_array($method, array('post', 'put', 'delete')))
  {
    return array($url, $method, $arguments);
  }
  else
  {
    $queryString = http_build_query($arguments, null, '&');
    $sep = false === strpos($url, '?') ? '?' : '&';

    return array($url.($queryString ? $sep.$queryString : ''), 'get', array());
  }
}

// fix for select multiple
// taken from http://stackoverflow.com/questions/3145068/set-multi-dimensional-array-by-key-path-from-array-values/3145199#3145199
public function findInArrayByArrayPath(&$array, &$path, $_i=0) {
  // sanity check
  if ( !(is_array($array) && is_array($path)) ) return false;
  $c = count($path); if ($_i >= $c) return false;

  if ($_i==0) {$path = array_values($path);} // to make sure we don't get skipped numeric keys which does happens in the preg_split above

  $k = $path[$_i];
  if (array_key_exists($k, $array))
    return ($_i == $c-1) ? $array[$k] : $this->findInArrayByArrayPath($array[$k], $path, $_i+1);
  else
    return false;
}

// fix for select multiple
public function unsetInArrayByArrayPath(&$array, &$path, $_i=0) {
  // sanity check
  if ( !(is_array($array) && is_array($path)) ) return false;
  $c = count($path); if ($_i >= $c) return false;

  if ($_i==0) {$path = array_values($path);} // to make sure we don't get skipped numeric keys which does happens in the preg_split above

  $k = $path[$_i];
  if (array_key_exists($k, $array))
    if ($_i == $c-1) {
      unset($array[$k]);
      return true;
    } else {
      return $this->unsetInArrayByArrayPath($array[$k], $path, $_i+1);
    }
  else
    return false;
}