If you add a computed field (string) to a node type and then create content, the computed value is calculated as desired. But if add the computed field after creating content, the computed value is never calculated. A computed field with integer value is never calculated, whether you add the field before or after creating content.

See example drupal installation with sqlite-database in the attachment. User and Password is "me"

Comments

Pepe Roni created an issue. See original summary.

mkolar’s picture

Same here.. looks like preSave in ComputedFieldItem is never called.

pepe roni’s picture

Except with varchar fields.
I have done a little bit debugging and found out, that, for integer fields, preSave is called for the parent classes only :(
Seems to be a misconfiguration in this module or a bug in core (I guess the latter).

But that does not explain, why computed fields added afterwards are never computed.

pepe roni’s picture

Below you can find two patches that may solve the following problems:
1. Numeric values are never calculated
2. If you add a computed field to bundles with existing content, these values never get calculated.

The second patch is a little trick. If you add a field of any type with default value to a bundle with existing content and that field is not displayed in an edit form, this field will stay empty. If you show it on an edit form, the value is saved as desired. So the second patch adds a widget for computed fields to enable (some) display on a form to save the computed value on form save. Later on, when all contents has been re-saved, you can move the fields to the disabled area.

This seems to work, but I have some intuition, that neither my patch, nor the whole module is following the Drupal-8-way of doing this. For example the method ComputedFieldItem->isEmpty() is called over and over again.

acbramley’s picture

Hey, I think the module is following Drupal8 standards, so don't worry about that. I'm not sure about the isEmpty() function running over and over but it probably is intended.

I think it would be better to investigate why preSave() is never run for numeric values before committing that patch. What if we added a new column to the field schema "has_been_computed" so we only ever compute the field once. I'm assuming isEmpty() gets run before the preSave() hence why the numeric values are potentially returning as empty? If we add a new column we could check if value has been computed already in executeComputedCode() and just return the value if it has.

I think adding a widget is also a good idea, you could set the #access flag to the value of has_been_computed, so if the value is computed, we hide the field, otherwise it gets displayed?

mkolar’s picture

Are you sure this affects only numeric values? I have pretty same problem with all of my custom field types (they are pretty similar to computed). All of them does not perform preSave on entities which were here before field. BTW even worse problem is with taxonomy vocabularies. I'm pretty sure preSave was never called even on new taxonomy terms, can anyone please confirm that?

pepe roni’s picture

StatusFileSize
new4.43 KB

the problems with isEmpty are:

  1. it is called for fields on the form only --> solved by adding a field widget.
  2. $value = $this->get('value')->getValue() mostly returns the value before editing the form (or the default value). Only if it is called immediately before preSave, it returns the edited value. With the addition of the field widget (default values '' or 0), it always returns a non-empty value, so isEmpty always returns TRUE (if you set the default values in the field widget to NULL, preSave will not be called!)

My patch "Allow_numeric_values_to_be_created" is indeed superfluous, as the other patch solved the problem, too.

I rewrote isEmpty to always return TRUE and the field widgets are now always be hidden (by setting the #access-property to FALSE).

pepe roni’s picture

StatusFileSize
new73.98 KB

I have rewritten the module to provide native field types with built-in formatters for these field types. Here is an excerpt from the README.md:

# Computed field
## Description
This is a complete rewrite of the former computed field module to separate field types more precisely.
It now provides five field types, whose values are computed by PHP-code you provide in the field settings.

* **Computed decimal**. A numeric field type with precision and scale, and optional prefix and suffix.
* **Computed float**. Another numeric field type with optional prefix and suffix.
* **Computed integer**. This is a numeric field type for numbers without decimals, with optional prefix and suffix.
* **Computed string**. This is a character field type with a given maximum of characters.
* **Computed string** (long). This is like above, but with unlimited length.

Besides the data types this module also provides some field formatters for each type, like the core field types:

* **Unformatted** displays the value as is.
* **Default** allows to add prefix, suffix, thousands separator (numeric field types only)

All these formatters allow to set cache duration. By default, cache settings are left untouched (default) which is in most cases correct. But if the PHP-code consists of volatile elements, like time/date dependent values you should set the cache duration accordingly.

**Attention!**

> Unlike prior versions computed fields don't have a display code anymore. This is due to the fact, that display code is formatting and formatting is not field definition. But now you can have different formatters for different view modes.

## Usage

* Download and install the module as usual. No additional configuration is needed.
* Add the computed field(s) to your bundles.
* Go to the tab "Manage form display" and at least save the form. This is **necessary**, even if you don't change anything else!
* If there is currently no content of that bundle, you can safely move the computed fields to the *Disabled* area. But if there is content, don't do that otherwise the computed values for existing content would not be created. Normally the fields are not displayed in the form unless you have defined the computed field as *multiple*. Then an (almost) empty table with drag options appears. This seems to be "normal" Drupal behaviour. You can solve this only by moving the computed field to the *Disabled* area with the implications above.
* Go to the tab "Manage display" and drag the field into the correct order. Then you can select and configure the formatter. **Don't forget to hit the *Save* button to store your changes** otherwise they are lost.
* It's always a good idea to **rebuild the cache** if you are playing around with the computed fields.

## Additional modules
There are two additional modules you could enable:
### Computed field example formatter
This module provides an example to create your own PHP formatter for a computed field. To do so see below.
### Computed field PHP formatter
This module provides the ability to define the formatter code on the fly everywhere a formatter can be specified (this is also true for views!). As this can be dangerous, especially if users can define their own views, activate this module only if really needed. It is almost better to define the formatter in a separate module than on the fly!

## Examples
### See the difference between cache *default* and cache *off* or *duration*
To see the effects of caching you can follow this little example:

* Add two computed integers to the bundle.
* In both field set the PHP code to "`$value = time();`".
* Go to *Manage form display* and hit *Save*.
* Go to *Manage display* and set caching in one of the field to *off* or a certain duration. Leave the other field as is! Hit *Save* again.
* Add content or view existing content for that bundle.
* Refresh the screen.

Now you can see that one field keeps its value while the other field counts the time (in intervals you have set with the cache duration).

*This does not work if you have developer settings with caching set off!*

### Create your own PHP formatter
To create you own PHP formatter, clone the provided **computed_field_example_formatter** as follows:

* create a new module folder *modules/my_module* or (better) *modules/custom/my_module*.
* copy the contents of the *computed_field_example_formatter* folder to *my_module*.
* rename *computed_field_example_formatter.info.yml* file to *my_module_formatter.info.yml*. Modify name and description within the file as needed.
* rename *ComputePhpFormatterExample.php* file (in *src/Plugin/field/FieldFormatter*) to *myModuleFormatter.php*
* in this file change all occurrences of *ComputedPhpFormatterExample* to *MyModuleFormatter*
* In the annotations section *@FieldFormatter* change *id* and *label* to your needs.
* Modify the body of the method *formatItem* as needed.
* Install your module, or rebuild the cache to let drupal read in the annotations, if your module is already installed.

## Credits
@todo: add credits

pepe roni’s picture

Status: Active » Needs review
pepe roni’s picture

@Martin (#6):
Indeed, if you add a field with default value to a bundle with existing content, you have to display the field on the edit form or you will never get the default value. This is true for core field types and also for custom field types. After saving all existing content everything seems to be ok. For new content, the fields do not need to be on the edit form. They are always created.

But this is not true for numeric fields :(
To create numeric fields with default values, the field *must* be displayed on the edit form. This is true for existing content as for new content.

"display" does not necessarily mean visible. You can add this field as a hidden field or set #access to FALSE in the render array of that field.

spazfox’s picture

This is a mammoth patch. :) Would it be possible for you to provide your entire rewritten module as a zip file to make it easier to install and test? Thanks.

pepe roni’s picture

StatusFileSize
new9.23 KB

I was supposed to submit the complete rewrite as a patch, so I did. But if you'd better like to have the complete module, here you are.

Thank you for testing ;)

alex72rm’s picture

Thank you very much! The output is displayed and all the commands (i.e. dpm from devel) work great!

I've a question about your decision to define different field types: I need to populate a link to a node entity... how to render it and which field type has to be used? A simple text?

pepe roni’s picture

Hi Alessandro,

up to now, you have to use a text field as you would do with the D7 version. But it is a good idea, to provide a computed field for nearly any field type. But not now. First my current changes must be reviewed and populated to the module.

alex72rm’s picture

Thanks a lot for your clarification.

Due to your experience, I try to explain my goal.

With devel's dsm function I've identified the D8 entity reference structure: I need to fill an array with a single nid:

$fields['field_xxx'][0]['target_id']=$my_NID;

But $fields isn't recorded outside the computed code scope, neither $value is usable because it cannot be tied to an array but only to the basic types you have defined.

Therefore... how to solve?

Thank you so much for your advice.

avibrazil@gmail.com’s picture

So Pepe Roni rewritten module on #12 works for me, finally.
How can we get it in the module page so we can install it with normal methods (drush etc) ?

avibrazil@gmail.com’s picture

Since the only module that really works is the #12 in this thread, I have no choice and will have to describe problems here too.

The code that I can write on Content Type's Manage Display doesn't work because it is apparently saved as non-valid PHP. It is saved as HTML ("\n" ➡ "<br/>") is not valid PHP.
Also, there should be a way to set a computed field without storage: no table should be created and no value should be computed on node save time. In this case, all the computation should happen through the code on Content Type's Manage Display.

pepe roni’s picture

PHP-Code works for me without any problems. You must not enter PHP-tags!

The problem with null value fields is: they won't be displayed by Drupal, thus the formatter code never called. Each computed field must have a value in the database to trigger the formatter. I currently haven't found a way to solve this, so I can't and won't fix this.

pepe roni’s picture

Perhaps dealancer, as the maintainer of the D8 version, can take a look on my work to publish or discard the code. I'm currently not allowed to.

After that I can check if and how to implement additional features as requested in #15

ckng’s picture

#12 works better. But re-saved the node in bulk via content admin view, the computed field is not updated. Individual saving the node, it works.

pepe roni’s picture

@#20: If the field was added afterwards, it will only be populated if the form is shown (but only if the field is not in the disabled area, as I described in the readme.md). If the field already has content and you change the php-code, the bulk update should work.

Later I will update the readme.md when my rewrite is accepted and published by dealancer.

ckng’s picture

It is make more sense and more practical to update computed field on entity presave? Imagine if you have 10K, 100K, or more to update. What do you suggest on how to update in bulk?

juliencarnot’s picture

Version in #12 works for me. Glad I finally found this issue and file after losing so much time trying to figure out why nothing happened with the version from the repo. Would be great if this one could be pushed so that people can keep on testing and improving it!

hedrickbt’s picture

I have tested #12 as well and it works great. Since the current D8 version of the module didn't work at all for me with Drupal 8.1.1+, what can I do to help getting #12 to replace the current downloadable one on the main module page?

I too noticed the issue that after making PHP code changes, I would have to go to each content item and re-save them for the computed value to update.

WARNING:
At least for me, I had to remove the previous content items and content types that were using Computed Field, and uninstall Computed Field, before I could update to #12. I was unable to just upgrade to #12. This would be another good reason to remove the one that is currently not working from the module page.

hedrickbt’s picture

Status: Needs review » Patch (to be ported)
ram4nd’s picture

Status: Patch (to be ported) » Reviewed & tested by the community
gaele’s picture

Priority: Normal » Major

"A computed field with integer value is never calculated", so this is at least major.

gaele’s picture

@ram4nd As this is a complete rewrite of the module, perhaps you should open a 8.x-2.x branch for this?

deminy’s picture

We started using #12 instead of 8.x-1.x-dev, and it works smoothly. For our project it's hard to switch back with 8.x-1.x-dev considering that computed fields have been populated with data and #12 is not compatible with 8.x-1.x-dev. I'd highly suggest to have a new branch (8.x-2.x) for #12. Thanks for the contributions!

hydra’s picture

#8 Is working for me, thx for sharing

ruy.guerra’s picture

#12 works perfectly and i've use on my production site with a lot of computed fields. I also would like to see #12 as a new branch (8.x-2.x).
This week, after a 8.2.0 Drupal core update, I noticed that empty computed fields are not hidden anymore. I'm very worried about the future of this module.

  • ram4nd committed 3997860 on 8.x-2.x authored by Pepe Roni
    Issue #2665434 by Pepe Roni: Computed values not computed
    
ram4nd’s picture

Status: Reviewed & tested by the community » Fixed

Used #12 for 8.x-2.x as suggested.

ram4nd’s picture

Version: 8.x-1.0-alpha1 » 8.x-2.x-dev

Status: Fixed » Closed (fixed)

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

pmunch’s picture

I used the D6 and D7 versions of this module a lot, one of my favorites for sure, but I'm really confused about major issues with D8 version...

I'm on a D8.2.5 install, and I was not able to have any value displayed ever (even a dummest static string) trying the 3 following versions, each fully uninstalled before the next one:
- 8.x-1.0-alpha1
- 8.x-2.x-dev
- Pepe Roni's #12 rewrite

I finally had #12 working but only on a node type created after module is installed... 0.o

8.x-1.0-alpha1 is now more than a year old, and not much seems to happen on 8.x-2.x-dev, so is this module still maintained ?

colan’s picture

#36: I need it so I'm trying to revive it. See #2587499: Port Computed Field to Drupal 8 for details.