Posted by fearlsgroove on August 19, 2011 at 2:39am
22 followers
| Project: | Drupal core |
| Version: | 7.x-dev |
| Component: | field system |
| Category: | bug report |
| Priority: | major |
| Assigned: | Unassigned |
| Status: | active |
| Issue tags: | Needs tests, translatable fields |
Issue Summary
If you add a list field (any data type), set it to multiple and provide a default value, it is impossible to deselect all options for the field. The field system sees that that no values are supplied and supplies the default value on save. The default value populates the form for the field, so if the user explicitly unchecks them, the field system should not inject it's own defaults instead.
Comments
#1
Indeed, I can reproduce with radios, checkboxes, but actually also for any field type and widget (e.g simple textfield widget for text or number fields).
1. Set a default value on a field
2. Go to the creation form for an entity using that field
3. Remove the pre-filled value (FAPI #default) and leave the field empty, save
4. The entity has the default value for the field.
This happens in field_default_insert(). Since #392696: Save default values on insert, default values get added on "entity insert" when the incoming $entity has no $entity->field_name property. That was to save default values on programmatic entity saves.
Later on, the 'Translatable fields' patch changed the condition, and default values get added also when
isset($entity->field_name[$langcode]) && count($entity->field_name[$langcode]) == 0Yet
$entity->field_name = array($langcode => array())is exactly what comes out of any field that was left empty.I cannot say I specifically remember the reasoning behind the code added by the TF patch, but it looks like we should rather check for
!isset($entity->field_name[$langcode]).We'll also need tests for this :-/.
#2
#3
The last submitted patch, field_default_value-1253820-1.patch, failed testing.
#4
Wait, doesn't work. The code comment specifically says "We also check that the current field translation is actually defined before assigning it a default value. This way we ensure that only the intended languages get a default value. Otherwise we could have default values for not yet open languages."
Then I think I'm a bit lost :
- if $entity->field_name[$some_lang] === array() (explicit empty field), we *don't* want a default value (currently broken in D8/D7)
- if $entity->field_name[$some_lang] === NULL, I'd say we *don't* want a default value either - an explicit NULL is understood as 'empty' in other parts of the code.
- if $entity->field_name[$some_lang] is not present, according to the code comment, we wouldn't want a default value, but then again that's precisely the case we wanted to address in #392696: Save default values on insert :
$new_node = (object) array('type' => 'article',
'title' => 'foobar',
'body' => array('und' => array(array('value' => 'my body', 'format' => 'filtered_html'))),
);
node_save($new_node);
The code specifies nothing for field_foo, which happens to be configured with a default value, which should then be inserted...
#5
Aw, this is pretty tricky: while introducing the new language key level the rule of thumb was "if in the old code
!isset($entity->field_foo)is valid in the new code, then!isset($entity->field_foo[$langcode])should be equally valid". Clearly this does not work here.This cannot work unless we are able to define a default value for the field language too:
<?php$new_node = (object) array(
'type' => 'article',
'title' => 'foobar',
'body' => array('und' => array(array('value' => 'my body', 'format' => 'filtered_html'))),
);
node_save($new_node);
$new_node->field_foo == array($default_language => array('value' => 'baz'));
?>
I don't think this needs to be a configurable value like the actual value, but it cannot be the default site language. It should be the entity language but we have no such concept in core atm. Anyway I'm going to post a clean up task issue, in order to respond to the many requests for a reliable
field_get_items()/field_set_items()pair, that should introduce it. I'll crosspost it here as soon as I write it.The alternative in the case of a non existing field property might be creating a default value for every available language, but I ain't sure this is a desirable default behavior.
#6
Maybe : create a default value for each language that is explicitly present in any of the other fields in the incoming entity ?
#7
I am afraid this cannot always work: suppose only untranslatable fields were provided, we would have no clue about which language pick up. IMO the test should be changed in the following way:
<?phpif ((empty($entity) || !property_exists($entity, $field['field_name']) ||
empty($entity->{$field['field_name']}[$langcode])) && $langcode == entity_language($entity_type, $entity)->language) {
?>
#8
#1260640: Improve field language API DX
#9
I might be missing something, but I'm not sure that's an issue - we're only dealing with programmatic creation of new entities here. The incoming $entity definition, containing the explicit data provided by the caller, is all we need to care about.
Proposal (assuming we're dealing with 'field_a', configured with a default value) :
- If field_a is not translatable, make sure it gets a value for 'und' language (filling in the default value if not)
- If field_a is translatable, make sure it has a value (filling in the default value if not) in every language present in any of the explicit field values present in the $entity (that is, every language explicitly 'opened' by the incoming $entity definition) - including 'und'.
If no language open (or if $entity has no explicit field value whatsoever) , make sure at least 'und' gets a value.
#10
I ain't sure this would fly: if a field is translatable it's not supposed to hold LANGUAGE_NONE values, unless the entity's language is LANGUAGE_NONE (which atm happens only for nodes). Creating an 'und' value for a translatable field belonging to a node having language 'en' would cause it to disappear from the node form.
IMO introducing an
entity_language()function working exactly asentity_label()should give us the default we need and should not be absolutely hard or tricky to implement.#11
#12
Fixing tag.
#13
Marked #1052070: If a field has a default value, it cannot be empty on insert. as duplicate.
#14
@yched: are you ok with #10?
#15
Sorry for the delay, I had a busy fortnight.
#10 will make it so that on a programmatic creation of an $entity spanning several languages, only the main language will receive default values. That sounds a bit unintuitive / inconsistent. Then again, I'm a bit baffled by the topic, so if that's the best we can do...
What about the following (modified from my #9 to address your #10) :
Assuming we're dealing with 'field_a', configured with a default value,
- If field_a is not translatable, make sure it gets a value for 'und' language (filling in the default value if not)
- If field_a is translatable, make sure it has a value (filling in the default value if not) in every language present in any of the explicit field values present in the $entity (that is, every language explicitly 'opened' by the incoming $entity definition) - not including 'und', but at least including the entity_language().
#16
I think this can work, any idea which should be the right place to make it happen?
#17
field_default_insert() is the place. I guess it could use a static var to extract the languages present in the incoming $entity on the 1st call (we can separate different entities because the new $entity being saved gets a nid before field_default_insert() gets called)
I'm leaving tomorrow for 3 weeks away from my coding env, so I probably won't be able to patch this myself, though :-/.
#18
Better title. Also, we should really start with tests here.
#19
I'll look into a test.
#20
Here is the entity language issue this one depends on for a proper solution: #1495648: Introduce entity language support.
#22
Attached exposes the bug.
#23
The last submitted patch, field_default_value.patch, failed testing.
#24
Re-rolled @xjm's test from #22 against HEAD.
#25
Let's ask the bot. It should fail once.
#26
The last submitted patch, field_default_value-1253820-24.patch, failed testing.
#27
Rerolled, going to take a look at a fix if I can.
#28
The last submitted patch, default-value-1253820-27.patch, failed testing.
#29
Yeah, I have no idea how to fix this. I think this one is on yched or fago.
#30
Working on this.
#31
@yched:
I think we have a problem with the proposed solution: it does not consider that empty submitted values are actually filtered out in
field_attach_submit(). This makes impossible to skip default values in this case.The attached patch + tests should fix this bug when doing programmatic insertions, I have no clue how to address this for form-driven insertions (AAMOF the related tests are failing). Any suggestion?
#32
The last submitted patch, field-default_value-1253820-31.patch, failed testing.
#33
#34
Just thinking out loud, but:
We now have entity_create(), that's used on both programmatic entity creation, and as a preliminary step when showing an "entity add" form.
I'm wondering if this would be the correct place to initialize default values.
Then both flows (programmatic creation & form creation) then become basically the same:
"here's a fresh entity with defaults prepopulated, you can now edit it".
This seems much more sound that what we currently do (populate defaults as default widget values in creation forms + force add them at save time, which clashes).
This being said, I haven't really looked at what the implementation might look like...
#35
#34 makes sense, although it's
hardlynot backportable. Here is a patch implementing it. There are some failing tests and API docs are missing, but this needs an architectural review before fixing those issues.#36
The last submitted patch, field-default_value-1253820-35.patch, failed testing.
#37
#38
I think so as well. For the Entity Field API we have #1777956: Provide a way to define default values for entity fields - let's sure to get it right there. Then for d8 we can inherit the solution by basing field API on the Entity Field API.
#39
What do you think about #35? Could we move the approach there in the other issue and expand it to the Entity Field API?
#40
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php@@ -444,6 +444,10 @@ public function create(array $values) {
+ // Modules might need to add or change the data intially held by the new
+ // entity object, for instance to fill-in default values.
+ drupal_alter(array($this->entityType . '_entity', 'entity'), $entity);
+
I agree that this hook is a good idea - I already thought about doing that also. Imho it should be hook_entity_create() and follow the entity+$entity_type hook pattern. "Act on entity creation." ?
There is a typo in "intially".
Still, I think it would be preferable to have default values applied via Entity Field API and keep the hook for any custom alterations of them.
Still, we could apply all default values there meanwhile?
Generally, I think the patch is a good improvement so I guess it's a good idea to do this now, while improving things with Entity Field API in a second step. Thus, setting to needs work for the hook name and docs.
#41
The logic around default values in WidgetBase::form() will need to be removed too.
#42
Also, per #31, I think we cannot fix this in D7 unless we do very radical changes to the current behavior, which I guess we don't want to do at this point of D7 lifecycle.
#43
This should address @fago's review.
#44
Ups, I missed #41. Here's a new one and an interdiff against #35.
#45
The last submitted patch, field-default_value-1253820-44.patch, failed testing.
#46
This should fix the latest failures hopefully.
#47
I thought we were close to RTBC with this: @fago or @yched can you confirm? This will help with the thresholds.
#48
+++ b/core/modules/field/field.moduleundefined@@ -387,6 +388,44 @@ function field_data_type_info() {
+ * @param $entity
+ * The entity for the operation.
+ * @param $langcode
+ * (optional) The field language to fill-in with the default value. Defaults
+ * to the entity language.
These need parameter typehints (no changes yet).
Attached is #46 with a test-only patch including my original test and other test hunks.
#49
Many thanks @plach !
phpdoc for field_populate_default_values():
+/**+ * Inserts a default value if no $entity->$field_name entry was provided.
+ *
+ * This can happen with programmatic saves, or on form-based creation where
+ * the current user doesn't have 'edit' permission for the field. This is the
+ * default field 'insert' operation.
This is directly copied from field_default_insert() but doesn't really reflect the new code flow now - this happens on entity_create(), so before and independently of both form submits and programmatic saves, and before an $entity->$field_name can even "be provided" ?
Also, do we really need those checks in the function now ? :
// We need to preserve existing values.+ if (empty($entity->{$field_name}) || !array_key_exists($field_langcode, $entity->{$field_name})) {
Probably related: I'm not sure about field_populate_default_values() as a standalone function. We only intend to do this on hook_entity_create(), not provide this as a general "you might want to do that too" API function, right ? (at least we currently don't, so I'm not sure we need to bother with this additional "api feature").
So maybe just inline the code in field_entity_create(), or at least use an underscored helper func ? (personal pref for the former I guess)
#50
The last submitted patch, field-default_value-1253820-46.patch, failed testing.
#51
#48: field-default_value-1253820-46.patch queued for re-testing.
#52
Right! Removed all that obsolete stuff and simplified the PHP doc as now there is not much to say about it. Fixed also missing type hints.
Yes. When calling
entity_create()you can pass an array of initial values, without those checks the default values here might override those. There is a new test covering this.The main use case I have in mind is supporting the ability of populating defaults when adding a translation: in that case you already have an existing entity object, but you need to fill-in the defaults for the new language.
#53
@plach #52 :
OK, makes sense. Where would that happen though ? In core ? In custom code ?
#54
I'm guessing in the Entity API, we will need to either introduce entity translation CRUD hooks or make entity translations entities, see #1810370: Entity Translation API improvements.
#55
OK, thanks for the explanation.
The changes here are fine by me, I'll let @fago vouch for the entity API part and set to RTBC.
#56
@fago already gave his ok in #40, except for two minor things fixed immediately afterwards :)Sorry, he didn't review the last entity API changes.
#57
I'm unsure here, as this would only cover defaults set by field module. Once we allow setting them via the hook you won't cover others. While this would be solved by having default-values as part of EntityNG/TypedData though, I think we should really start flushing out entity translation-crud API design now (or leave it).
Summarized, I'd see the in-line variant as the right solution, but we can still inline it once we've solved the translation use-case otherwise.
+++ b/core/includes/entity.api.php@@ -56,6 +56,18 @@ function hook_entity_info_alter(&$entity_info) {
+ * Act on entity creation.
+ *
+ * @param Drupal\Core\Entity\EntityInterface $entity
+ * The entity object.
Sounds good. Maybe, should we mention in an extra line that this may be used to set custom default values?
+++ b/core/includes/entity.api.php@@ -56,6 +56,18 @@ function hook_entity_info_alter(&$entity_info) {
+function hook_entity_create(Drupal\Core\Entity\EntityInterface $entity) {
This, adds hook_node_create() and so on also - thus we should create respective API docs for all entity types also.
+++ b/core/includes/entity.api.php@@ -56,6 +56,18 @@ function hook_entity_info_alter(&$entity_info) {
+ if (!isset($entity->foo)) {
+ $entity->foo = 'bar';
+ }
Minor, but let's do an example that already uses Entity-NG here? -> Less code to convert.
+++ b/core/lib/Drupal/Core/Entity/Entity.php@@ -263,7 +263,8 @@ public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User
- return !empty($this->langcode) ? language_load($this->langcode) : new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED));
+ $language = !empty($this->langcode) ? language_load($this->langcode) : FALSE;
+ return $language ?: new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED));
Seems to be an unrelated change? Howsoever, I'm not sure the new code is better than the old one. Maybe just convert it to multiple lines using if()/else()?
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php@@ -145,7 +145,13 @@ function postComment($node, $comment, $subject = '', $contact = NULL) {
- return entity_create('comment', array('id' => $match[1], 'subject' => $subject, 'comment' => $comment));
+ $values = array(
+ 'id' => $match[1],
+ 'node_type' => is_object($node) ? 'node_comment_' . $node->bundle() : '',
+ 'subject' => $subject,
+ 'comment' => $comment,
+ );
+ return entity_create('comment', $values);
This clashes with the comment-conversion patch, which contains a proper fix for it (loading the comment). But, if this one goes in first it should be fine as interim improvement.
Setting to needs-work for the per entity-type API docs.
#58
Here is a patch adding the missing PHP docs.
It's needed to make a test pass: previously if you created an entity using a non exisiting language code the language() method returned false, which made lots of things go wrong.
#59
+++ b/core/modules/file/file.api.php
@@ -7,6 +7,21 @@
+ * This can be used to set initial values for the file, for instance to
+ * provide defaults.
+++ b/core/modules/node/node.api.php
@@ -535,6 +538,23 @@ function hook_node_insert(Drupal\node\Node $node) {
+ *
+ * This can be used to set initial values for the node, for instance to
+ * provide defaults.
+++ b/core/modules/taxonomy/taxonomy.api.php
@@ -110,6 +125,21 @@ function hook_taxonomy_vocabulary_delete(Drupal\taxonomy\Plugin\Core\Entity\Voca
+ * This can be used to set initial values for the term, for instance to
+ * provide defaults.
+++ b/core/modules/user/user.api.php
@@ -13,6 +13,21 @@
+ * This can be used to set initial values for the user, for instance to
+ * provide defaults.
Comment not wrapping correctly.
#60
+++ b/core/lib/Drupal/Core/Entity/Entity.php@@ -263,7 +263,8 @@ public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User
- return !empty($this->langcode) ? language_load($this->langcode) : new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED));
+ $language = !empty($this->langcode) ? language_load($this->langcode) : FALSE;
+ return $language ?: new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED));
I see. In entityNG we have this workaround for the same problem:
/*** Implements TranslatableInterface::language().
*/
public function language() {
$language = $this->get('langcode')->language;
if (!$language) {
// Make sure we return a proper language object.
// @todo Refactor this, see: http://drupal.org/node/1834542.
$language = language_default();
}
return $language;
}
Can we unify the work-a-rounds? LANGUAGE_NOT_SPECIFIED sounds reasonable.
Also could we just use if/else instead of ?: - imho having multiple lines of ?: statements is too much.
Is there a difference between initial values and default values?? If not, let's just use "This can be used to set custom default values for entity fields."
#61
This should unify
Entity::language()andEntityNG::language()as much as possible. We will be able to rely onhook_entity_create()in the Language module to provide an initial value of thelangcodekey based on the content language setting, thus effectively removing the possibilty of not having a valid langcode in most situations.Well, actually "initial" sounds slightly more generic to me: the new hook could be used to provide a value just in a particular circumstance. In this case I wouldn't call it a default value.
#62
Thanks, improvements look good!
I see, ok.
Sry for not coming up with this previously, but I just realized that the hook description might be confused by devs with hook_comment_insert(). Let's clarify this better. Also, what we are acting on is the entity (object) so what about that:
* Act on a newly created comment.*
* This hook runs after a new comment object has been created, without
* permanently saving it. It can be used to set initial values for the comment,
* for instance to provide defaults.
?
Then, another thing we missed previously: field_entity_create() should check whether the entity is fieldable.
#63
Added the fieldable check and improved PHP docs. I slightly adjusted your suggestion, because I think that the "instantiation" term should give a developer a clear idea of which phase we are talking about. I also streamlined the following sentence a bit to avoid repetitions.
#64
+++ b/core/modules/comment/comment.api.php@@ -49,6 +49,21 @@ function hook_comment_update(Drupal\comment\Comment $comment) {
+ * This hook runs after a new comment object has just been instantiated. It can
+ * be used to set initial values, e.g. to provide defaults.
Works for me - I'd just remove the "just" as we do not use it other hook descriptions either.
#65
Here it is :)
#66
Thanks - looks good.
#67
+++ b/core/modules/comment/comment.api.phpundefined
@@ -49,6 +49,21 @@ function hook_comment_update(Drupal\comment\Comment $comment) {
+++ b/core/modules/file/file.api.phpundefined
@@ -7,6 +7,21 @@
+function hook_file_create(\Drupal\file\Plugin\Core\Entity\File $file) {
+++ b/core/modules/node/node.api.phpundefined
@@ -535,6 +538,23 @@ function hook_node_insert(Drupal\node\Node $node) {
+function hook_node_create(\Drupal\node\Plugin\Core\Entity\Node $node) {
+++ b/core/modules/taxonomy/taxonomy.api.phpundefined
@@ -13,6 +13,21 @@
+function hook_taxonomy_vocabulary_create(\Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary) {
@@ -110,6 +125,21 @@ function hook_taxonomy_vocabulary_delete(Drupal\taxonomy\Plugin\Core\Entity\Voca
+function hook_taxonomy_term_create(\Drupal\taxonomy\Plugin\Core\Entity\Term $term) {
+++ b/core/modules/user/user.api.phpundefined
@@ -13,6 +13,21 @@
+function hook_user_create(\Drupal\user\Plugin\Core\Entity\User $user) {
I think these should be generically in entity.api.php as hook_ENTITY_TYPE_create()
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.phpundefined@@ -145,7 +145,13 @@ function postComment($node, $comment, $subject = '', $contact = NULL) {
+ $values = array(
+ 'id' => $match[1],
+ 'node_type' => is_object($node) ? 'node_comment_' . $node->bundle() : '',
+ 'subject' => $subject,
+ 'comment' => $comment,
+ );
+ return entity_create('comment', $values);
You could still avoid the extra $values, just have
entity_create('comment', array(...
);
on multiple lines
#68
While this is a good suggestion, it's not what we do currently. We should follow the current way of doing things and address this question in a general issue for all entity_* hooks, i.e. #1824184: Remove and replace entity type specific API hook documentation with generic entity API hook documentation.
#69
I agree with @fago: let's stick with the current way of doing things for now. If/when the documentation policy changes all the docs will be updated together.
The attached patch inlines the
$valuesarray, although I don't see it exactly as a readability improvement.#70
ok, back to RTBC then.
#71
Ah, sorry! I often forget if policy changes like that have been adopted already, I was indeed thinking of that exact issue. Carry on. :)
#72
+++ b/core/includes/entity.api.php@@ -56,6 +56,21 @@ function hook_entity_info_alter(&$entity_info) {
/**
+ * Act on a newly created entity.
+ *
+ * This hook runs after a new entity object has just been instantiated. It can
+ * be used to set initial values, e.g. to provide defaults.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ * The entity object.
+ */
+function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
+ if (!isset($entity->foo)) {
+ $entity->foo->value = 'bar';
+ }
+}
+
What's not stated in the docs or clear from the name 'foo' is that this is only needed for entity fields/properties that aren't managed by field.module.
Also this example and the ones for the specific entity type hooks (hook_node_create(), etc.) assume EntityNG, but that's not stated anywhere, so if someone copies this documentation into a module they're working on now, it won't work. Perhaps a @todo would help clarify.
Unless someone beats me to it, I'll give the docs here a crack in a couple hours to keep this moving.
#73
Actually this would be false :) As I was saying in #61, the new hook could be used to provide a value just in a particular circumstance. In this case I wouldn't call it a default value and it wouldn't necessarily handled by the Field API.
Agreed with the @todo.
#74
Added @todo.
#75
How about this? Similar spirit on the hook_entity_create() example, but for the specific entity types, matches what's already in HEAD for the _load() hook. Both will need to be converted as part of each entity type's conversion to EntityNG, but it shouldn't be harder to convert both together than just the _load() one alone, and in the meantime, we keep them consistent with each other.
#76
Works for me.
#77
Yep, indeed the docu should match the current state of the API. +1
#78
#75: field-default_value-1253820-75.patch queued for re-testing.
#79
I reviewed the patch and it looks good at first sight. Could have done a more in-depth review though. Stopped reviewing this patch because I don't think it currently applies. Asked for a re-test.
#80
The last submitted patch, field-default_value-1253820-75.patch, failed testing.
#81
Rerolled
#82
hm
#83
Reroll looks good. Back to RTBC then.
#84
Alex and I actually spent a bit of time walking through this the other day, and I think it's good to go.
Committed and pushed to 8.x. Thanks!
We should add a change notice for this.
#85
Here is the change notice:
http://drupal.org/node/1891514
#86
Any reason that invokeHook() wasn't added to ConfigStorageController as well?
#87
I think it's just an oversight :)
Small follow-up?
#88
Here is a fix for #86. Btw, I think we should provide an abstract common ancestry to config and content entities when working on storage-agnostic entities and the Storage API.
Edit: I meant config and content entity storage controllers, obviously :)
#89
The change notice is confusing:
Does that mean that after installing the entity providing module the first ever entity_create('foo') fires this hook or that on every request the first call to entity_create('foo') fires the hook? If the latter...
#90
Nope, I just meant that it's fired on every
entity_create()but not when instantiating the object on entity load. Tried to make the first paragraph more clear.#91
Thanks for #88
#92
Hm. Seems like it should be possible to write a test for #86/#88, no?.
#93
Hm, I do not see a new revision on the change notice.
#94
@chx:
In #90 I was referring to this:
http://drupal.org/node/1891514/revisions/view/2523892/2523960
#95
That's not helping at all. You need to clarify whether "first time" means install time (more or less) or per request first time.
#96
Ok, I removed the "first time" terminology since it is misleading. Hope now it looks better.
The attached patch provides test coverage for #88. There's also a test only version to prove it.
#97
hm, I think the change notice was unnecessarily complex so I revised it. I also removed the field API example and replaced it by a simpler one. So what about that? http://drupal.org/node/1891514
#98
True - that said we already have an EntityCRUDTestCase which tests for hook invocations. We should test this hook there also.
#99
I think the new version lost lots of useful information about the entity-type specific version of the hook and the main rationale behind it. Anyway, it seems I couldn't get anyone to like it so let's call that part closed.
#100
Let's see what the bot thinks about this.
#101
Sorry, this is the correct interdiff.
#102
#100 addresses @webchick's and @fago's concerns so back to RTBC.
#103
Awesome! Glad to see that the tests helped flesh out a few more places we needed this. Sorry for the hassle.
Committed and pushed to 8.x. Thanks!
#104
Awesome, thanks!
#105
If a poor soul reaches this thread and really needs a solution for D7, here's what I did:
Implement a hook_form_alter() like this:
<?phpfunction mymodule_form_node_form_alter(&$form, &$form_state, $form_id) {
$is_new = !empty($form['nid']) && $form['nid']['#value'] == NULL;
// The node is new and the field exists in that content type
if($is_new && !empty($form['field_myfield'])){
$form['#submit'][] = 'mymodule_blank_values_submit';
array_reverse($form['#submit']); // First call mymodule_blank_values_submit()
}
}
?>
And set a flag in the node object to be used later if the value in the $form_state is an empty string.
The submit callback looks like this:
<?phpfunction mymodule_blank_values_submit(&$form, &$form_state) {
if($form_state['values']['field_myfield'][LANGUAGE_NONE][0]['value'] === ''){
$form_state['node']->data['empty_myfield'] = TRUE;
} else {
$form_state['node']->data['empty_myfield'] = FALSE;
}
}
?>
And finally to check if the node object has the flag with hook_node_insert(), and empty the field value:
<?phpfunction mymodule_node_insert($node){
if(!empty($node->field_myfield) && $node->data['empty_myfield']){
$node->field_myfield[LANGUAGE_NONE][0]['value'] = '';
}
}
?>
#106
Automatically closed -- issue fixed for 2 weeks with no activity.
#107
i just stepped on this:/
@panche i couldnt make it work with hook_node_insert..even if fields are actually saved after the hook, it wouldnt work, so i used hook_node_presave.
also no need for the form alter, hook_node_submit also works..here is how i did it:
<?php
/**
* Implements hook_node_submit().
* Workaround a core bug that wont be fixed in d7
* @see <a href="http://drupal.org/node/1253820
" title="http://drupal.org/node/1253820
" rel="nofollow">http://drupal.org/node/1253820
</a> */
function MYMODULE_node_submit($node, $form, &$form_state) {
if ($node->nid === NULL && isset($form_state['values']['field_myfield'])) {
$node->temp['empty_field_myfield'] = $form_state['values']['field_myfield'][LANGUAGE_NONE][0]['value'] === NULL;
}
}
/**
* Implements hook_node_presave().
*/
function MYMODULE_node_presave($node) {
// @see MYMODULE_node_submit().
if(!empty($node->field_myfield) && !empty($node->temp['empty_field_myfield'])) {
$node->field_myfield = array();
}
}
?>
#108
related? #1500214: Optional radio button value saves as default value, if N/A selected
#109
This is still an active bug for Drupal 7, though sounds like a different approach than the Drupal 8 patch will be needed?
#110
I thought that per #31 we agreed that we cannot fix this in D7 without making very radical changes.