Currently 'multiple' widgets (one form widget accepts multiple values input) need to validate that the number of values does not exceed the field cardinality. Both option.module's widgets and the newly added "autocomplete widget for 'taxo term' field" have code to handle that.

This check should be hardcoded in a default validation step for all fields, whatever the widget.
That check should happen in a new field_default_validate() function in field.default.inc, invoked by a _field_invoke_default('validate') call in field_attach_validate().
Saves duplicated code, and also accounts for pure API, non-form saves, which we are supposed to support.

Kind of related to (but not duplicate of) #437604: Do not rely on FAPI for 'required' validation.

No API change involved, can happen post-freeze IMO.

Comments

yched’s picture

Title: Validation of the number of values in feild_default_validate() » Validation of the number of values in field_default_validate()
Issue tags: +Fields in Core

fix title, add tags

HeraChen’s picture

Title: Validation of the number of values in field_default_validate() » how to save image into database after Upload and review?
Component: field system » image system
Category: task » feature

pls help me. thanks a lot

yched’s picture

Title: how to save image into database after Upload and review? » Validation of the number of values in field_default_validate()
Component: image system » field system
Category: feature » task

@HeraChen: you should try the regular places for support: http://drupal.org/forum, or irc://irc.freenode.net/drupal-support.
Please don't hijack existing issues.

yched’s picture

See the OP for the rationale.

Patch summary:
- adds a field_default_validate() operation, called through _field_invoke_default() in field_attach_validate().
that's a generic equivalent to the field-type-specific validation done in hook_field_validate().
- copying the PHPdoc from hook_field_validate(), I removed comments about field_attach_query() that don't apply anymore.
- removes the specific cardinality checks that were done in options.module and taxonomy.module

+ test stuff:
- adds a test for API validation in FieldAttachOtherTestCase::testFieldAttachValidate()
- adds a test for form-based validation in FieldFormTestCase.
- this test uses the assertListValues() helper function, moved from from options.test into field.test. Quite handy to have it there.
- this test uses a 'multiple value' widget implemented in field_test.module (simple comma-separated input).

Note that actual code change is 7k, the rest is tests ;-)

yched’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new21.81 KB

Small error in test_field's hook_field_widget(). Attached patch should fix the failures.
The 'no_test' patch in #4 is unchanged.

dries’s picture

+++ modules/field/field.attach.inc	24 Nov 2009 12:19:17 -0000
@@ -690,6 +690,7 @@ function field_attach_load_revision($obj
+  _field_invoke_default('validate', $obj_type, $object, $errors);
   _field_invoke('validate', $obj_type, $object, $errors);

This could do with a small code comment to explain the purpose of each call, and their order. Why do we need to have two layers of validation functions?

yched’s picture

Comment added:

  // Check generic, field-type-agnostic errors first.
  _field_invoke_default('validate', $obj_type, $object, $errors);
  // Check field-type specific errors.
  _field_invoke('validate', $obj_type, $object, $errors);
yched’s picture

yched’s picture

Assigned: Unassigned » yched

Easier tracking.

dries’s picture

A couple of points/questions:

+++ modules/field/field.default.inc	2 Dec 2009 23:36:07 -0000
@@ -21,6 +21,51 @@ function field_default_extract_form_valu
+  // Filter out empty values.
+  $items = field_set_empty($field, $items);

This snippet didn't make sense to me. I had to look at field_set_empty() to actually make sense of it, which is not a good sign. Either the code comment needs to be improved, or the function field_set_empty() needs to be renamed to be more self-explanatory. In fact, field_set_empty() has a todo * TODO D7: poorly named... -- it wouldn't hurt to rename the function.

+++ modules/field/field.default.inc	2 Dec 2009 23:36:07 -0000
@@ -21,6 +21,51 @@ function field_default_extract_form_valu
+  if ($field['cardinality'] >= 2 && $field['cardinality'] != FIELD_CARDINALITY_UNLIMITED) {
+    if (count($items) > $field['cardinality']) {

Does this test make sense? What if $field['cardinality'] == 1 but count($items) != 1 ... we wouldn't trigger an error. If this is a generic validation handler, we might want to make it 100% generic?

+++ modules/field/tests/field.test	2 Dec 2009 23:37:30 -0000
@@ -1597,6 +1628,46 @@ class FieldFormTestCase extends FieldTes
+   * Tests widgets handling multiple values..

Only needs one point.

yched’s picture

StatusFileSize
new25.28 KB

1) OK, renamed field_set_empty() to _field_filter_items() to keep symmetry with the sister helper func _field_sort_items(). Also refreshed the PHPdoc a bit.

2) You're right of course. I copied the structure of this code from option widgets, which didn't need to care for "cardinality = 1", because this case was ensured by form structure and FAPI. Fixed.

3) Fixed.

yched’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new24.83 KB

Rerolled.

+ tentatively setting to RTBC, since Dries remarks were adressed.

dries’s picture

Status: Reviewed & tested by the community » Fixed

Looks good now. Committed to CVS HEAD. Thanks!

carlos8f’s picture

Title: Validation of the number of values in field_default_validate() » [BROKE TESTS] Validation of the number of values in field_default_validate()
Category: task » bug
Priority: Normal » Critical
Status: Fixed » Needs work

This patch broke OptionsWidgetsTestCase, since it uses methods which are undefined in the class inheritance. This is another fire we have to put out before #560646: Fatal PHP errors don't cause tests to fail can land, so we can fix the test bot which is currently totally blind to these errors. The first one is:

Fatal error: Call to undefined method OptionsWidgetsTestCase::assertFieldValues() in modules/field/modules/options/options.test on line 88

Most of the field tests extend DrupalWebTestCase, which isn't logical since there is already a parent class for them to use, FieldTestCase. I tried to create a patch, but I could not get OptionsWidgetsTestCase to extend FieldTestCase (which has the methods in question), because I am getting some random crash:

Fatal error: Undefined class constant 'MYSQL_ATTR_USE_BUFFERED_QUERY' in includes/database/mysql/database.inc on line 31

Which I think is related to my installation of PDO. Anyhow, we need to fix OptionsWidgetsTestCase fatal errors. Then I want to create an issue examining the class inheritance in our tests.

Also, I just noticed this, list.test (a required module) implementing:

class ListFieldUITestCase extends FieldUITestCase {

which inherits from field_ui.test (an optional module), this is totally whacked out :P

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new686 bytes

class ListFieldUITestCase extends FieldUITestCase { was introduced in #653940: Clean-up: Tests do not report all errors:
http://drupalcode.org/viewvc/drupal/drupal/modules/field/modules/list/li...

Attached patch should fix the "undefined method OptionsWidgetsTestCase::assertFieldValues" fails.

carlos8f’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Quick fix

yched: thanks.

webchick’s picture

Title: [BROKE TESTS] Validation of the number of values in field_default_validate() » Validation of the number of values in field_default_validate()
Status: Reviewed & tested by the community » Fixed

Committed to HEAD. Thanks!

yched’s picture

@carlos8f :
class ListFieldUITestCase extends FieldUITestCase is fixed in #639466-23: hook_options_list() + XSS filtering

Status: Fixed » Closed (fixed)
Issue tags: -Quick fix, -Fields in Core

Automatically closed -- issue fixed for 2 weeks with no activity.