- π§π·Brazil cassioalmeida
I closed the MR until I didn't have the time to work on a complete solution.
That said, I don't believe that passing the responsibility of knowing the underline implementation of a method called isEmpty will return true only once for the Boolean field, a good thing.
Mainly because it's not the same behavior for other field types, although they share the same interface.
The interface docs mention the expected results:
Drupal\Core\TypedData\ComplexDataInterface
/** * Determines whether the data structure is empty. * * @return bool * TRUE if the data structure is empty, FALSE otherwise. */ public function isEmpty();
Beyond that, we have a "field-especific method" - we can see it on other field types. For example:
Drupal\Core\Field\Plugin\Field\FieldType\EmailItem
overwrites the isEmpty method and checks for the value:Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem
also does it.Drupal\Core\Field\Plugin\Field\FieldType\StringItemBase
andDrupal\Core\Field\Plugin\Field\FieldType\UriItem
too.No matter how many times you edit a node, all those fields, if the field value is empty, the method isEmpty return true; if not, false.
The goal is to:
1-) Avoid custom code to check if the field is empty by accessing its value.
2-) Expect the exact behavior of fields that implements the interface. - πΊπ¦Ukraine gilmord πΊπ¦Ukraine
Hi @cassioalmeida
Again - this makes no sense to push this issue
It looks like you are confused by the "Checkbox" form widget, as it looks the same for NULL and for FALSE
Please try using the Radio Buttons widget, and you will see the boolean field has actually 3 options:
- NULL
- FALSE
- TRUEAnd only NULL is EMPTY, FALSE and TRUE are NOT EMPTY
and this is how the isEmpty() works now, and it is logical.
Treating the value FALSE as EMPTY is not logical.Please see the attached image:
radios βNo matter how many times you edit a node, all those fields, if the field value is empty, the method isEmpty return true; if not, false.
This is the wrong statement. use Radio Buttons and set the field value to empty as many times as you want, not only once.
1-) Avoid custom code to check if the field is empty by accessing its value.
This is wrong also. You do not need to check value to know if the field is empty. You can use the isEmpty() method. If you want to check if the field value is FALSE - you HAVE to check the field value. Do not mix EMPTY and FALSE.
Please stop pushing this.
- π¬π§United Kingdom jonathanshaw Stroud, UK
@gilmord is right AFAICS.
In php
empty(FALSE ) === TRUE
. But the semantic of empty is just different in Drupal.Drupal's semantic is more like php's
is_null()
thanempty()
.
is_null(FALSE ) === TRUE
- π§π·Brazil cassioalmeida
Thanks for the explanation.
This is the wrong statement. use Radio Buttons and set the field value to empty as many times as you want, not only once.
That statement was about the EmailItem and some other classes under the namespace
Drupal\Core\Field\Plugin\Field\FieldType;
I did the following test β a CT with two fields. Email and Boolean (checkbox widget).
Then I created a node and left both fields without filling them out.
Then, on a node preprocess, I created the following example://Boolean field $node->get('field_featured')->isEmpty(); //Email field $node->get('field_email')->isEmpty();
The result of calling isEmpty on the Email field changes every time I update the node. If I save the node with some value in the Email field, the isEmpty result is false; if I update the node and leave the field without any value, the result of isEmpty is true. So, in that case, I can "trust" the isEmpty method to check against the value.
Probably that was the motivation to create the issue. By using the Radio widget as an example, it does make sense. But this thread can clarify for anyone in the future looking for why it "does not work" for Boolean fields.
- Issue was unassigned.
- π©π°Denmark Steven Snedker
Boolean field can have 2 states:
- NULL - the entity was never saved with the field, the field is empty
- 0/1 - the field has a valueA boolean with three values (NULL, 0, 1) has no upside whatsoever. At least I cannot imagine a single example where it's nice or convenient to use a boolean field to find out if a user has saved his/her user profile, webform or some node.
Booleans with three values (or two states and two values) makes a routine entityQuery awfully complex.
Here's an example:
$query = \Drupal::entityQuery('node') ->condition('type', 'measurement_result') ->condition('has_been_processed.value', 1, '!=') ->sort('changed', 'DESC') ->range(0, 20) ->accessCheck(FALSE) ->execute();
will not give me the 0 and NULL nodes. Only the has_been_processed=0 nodes.
So I have to make an additional
$query = \Drupal::entityQuery('node') ->condition('type', 'measurement_result') ->notExists('has_been_processed.value') ->sort('changed', 'DESC') ->range(0, 20) ->accessCheck(FALSE) ->execute();
"Ah," you may say. "You can make that more compact. Try:
$orGroup = $query->orConditionGroup() ->condition('field_saved_as_single.value', 1, '!=') ->notExists('field_saved_as_single.value');
But no. That does not work. notExists's and isEmpty's are not welcome in orConditionGroup's.
Is there a simpler way to find out if a checkbox has been checked?
And if not, can we make it? - πΊπ¦Ukraine gilmord πΊπ¦Ukraine
Hi @Steven Snedker
This question is not new, and it was discussed many times with the core contributors. Long story short - it works as designed (=
The "good" way for your case (get unchecked and never checked) will be to force 0 as a default value.
But here comes the problem - what if you add a boolean field to the existing entity? The problem appears when you have millions of existing entities.
It does not allow us to implement any fast filling of the values - it can get timeouts and staff like that.
So this has to be handled by the developer by adding batch processing, like Drush command or views bulk operation. There are contrib options for that - https://www.drupal.org/project/field_defaults βI suppose this is the main reason we face empty values - as you can see here https://www.drupal.org/project/drupal/issues/1919834 β - it works as designed (you can check the thread to find explanations).
Another possible option is to use a query instead of an entity query and use the LEFT JOIN to relate the boolean field table.
- πΊπ¦Ukraine gilmord πΊπ¦Ukraine
A boolean with three values (NULL, 0, 1) has no upside whatsoever. At least I cannot imagine a single example where it's nice or convenient to use a boolean field to find out if a user has saved his/her user profile, webform or some node.
Sounds right, but as far as a boolean is not just a value but a separate table - the problem appears, you have to JOIN the table to use it, and default join (INNER JOIN) will skip rows with unexisting values, and LEFT JOIN is much heavier to execute.
Just thought of one more workaround for you - you can add boolean field as a base property ( https://www.drupal.org/docs/drupal-apis/entity-api/defining-and-using-co... β ).
It can inherit all the benefits of the field but will be stored in the base entity table as single column. Like a "status" of the node.
I think this will simplify the queries as there will be no need to join the boolean table.The bad side of this option - you may end up with many extra columns in the base entity table.
- π©π°Denmark Steven Snedker
You are absolutely correct. I added a boolean field to an existing content type and pretty soon had
"NULL" in 5000 nodes
"0" in 200 nodes
"1" in 150 nodesLoading all nodes without "1" took two fairly long entityqueries.
That sucks.
Thank you for pointing me to Field Defaults β
That is the fastest, most robust and least sucky solution to this unfortunate problem.
Base property is a novel solution and creative. Well spotted. But knowing how Drupal is increasingly creaking under it's own weight I'll go with the simpler Field Defaults β solution.
Thanks a lot for the answer.