- Issue created by @wxman
- 🇬🇧United Kingdom joachim
📌 Allow adding computed bundle fields in Views Fixed would allow bundle fields to be output. Base fields apparently already can be output.
However, currently no kind of computed field is picked up automatically by Views data.
I'm pondering how best to fix this.
Probably a core patch for base fields & module code for bundle fields.
- 🇬🇧United Kingdom joachim
I've made a core patch that declares base computed fields to views: 📌 Automatically declare computed base fields to Views Needs work .
- 🇺🇸United States wxman
joachim - I checked on #3 and am I missing seeing the patch? I don't have a lot of experience with core patches so maybe I'm just missing it?
- 🇬🇧United Kingdom joachim
I can report that computed fields added in the UI work fine with the patch from 📌 Allow adding computed bundle fields in Views Fixed -- though you need to declare them in code as well.
- 🇺🇸United States wxman
@joachim I have set up two test sites, one running D9.x and the other 10.x. The 9.x site I installed Version: 4.0.0-alpha3 of Computed Field, and it's working as designed, except for not being accessible in Views.
I have applied patch: https://git.drupalcode.org/project/drupal/-/merge_requests/2511.patch.
Above you say "-- though you need to declare them in code as well". Where do I declare the field in code? If I figure that out is that going to make it able to be used in Views? - 🇬🇧United Kingdom joachim
> Where do I declare the field in code?
https://api.drupal.org/api/drupal/core%21modules%21views%21views.api.php...
- 🇺🇸United States wxman
Do I add that to a new custom module, or to the custom module I made at /web/modules/custom/buy_amazon?
/web/modules/custom/buy_amazon/src/Plugin/ComputedField/Computedbuyamazon.php - 🇬🇧United Kingdom joachim
It makes sense to put it in the same module as your computed field plugin, as both are required to make the field work.
- 🇺🇸United States wxman
I guess I'm going to have to wait till it gets fixed in Views. No matter what I try it still will not show in my View.
- 🇦🇹Austria maxilein
I could not wrap my head around building a plugin. Since I needed a solution a went back to a more traditional approach:
1. create a core field
2. create code in mmodule_ ...
mymodule_node_presave($entity) { switch ($entity->bundle()) { // Here you modify only your day content type case 'entity_machine_name': if (!empty($entity->field_name->value)) { ... do some custom calculation stuff
3. Make the field readonly in the form edit using Readonly Field Widget →
It is not as elegant as computed_field, but to me it was less time consuming, because I just did not comprehend the requirements and options for a plugin.
- 🇬🇧United Kingdom joachim
> I just did not comprehend the requirements and options for a plugin.
Could you explain more about the problem in a separate issue please? The plugins for computed fields are really pretty simply as plugins go, and there are examples in the module to draw from.
- 🇦🇹Austria maxilein
That is not a problem only of this module. It is a fundamental problem of Drupal. That's why I try to help with explanations wherever I can.
It may be pretty obvious for someone who programs Drupal for years. I could not get a proper article that leads me step by step. The explanations are extremely short.I try to avoid customizations, for easier upgrades. I do not want to read the source code in order to understand the basic purpose or principle of a module. At least not until I decided that a module could fit my purpose.
In this case: if I have to do coding anyway, why shouldn't I do in a way that seems less complex?
No offense! - 🇬🇧United Kingdom joachim
I really REALLY suggest you all use Module Builder. It will generate the plugin class for you.
- 🇦🇹Austria maxilein
joachim, please don't get me wrong. You are outstanding in all your efforts! And documenting much better than most of Drupal developers!
- 🇬🇧United Kingdom joachim
Thanks! :)
I've started some docs - https://www.drupal.org/docs/extending-drupal/contributed-modules/contrib... →
Incomplete, but will add to them when I have time.
- 🇺🇸United States wxman
Here is the module I made to go with my "computed_buy_amazon" computer field. It's at: buy_amazon\src\Plugin\ComputedField\ComputedField.php
namespace Drupal\buy_amazon\Plugin\ComputedField; use Drupal\Component\Datetime\TimeInterface; use Drupal\computed_field\Field\ComputedFieldDefinitionWithValuePluginInterface; use Drupal\computed_field\Plugin\ComputedField\ComputedFieldBase; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * @ComputedField( * id = "buy_amazon_computedbuyamazon", * label = @Translation("Computed buy Amazon"), * field_type = "text", * attach = { * "scope" = "base", * "field_name" = "buy_amazon_computedbuyamazon", * "entity_types" = { * "entity_test" = {}, * }, * } * ) */ class Computedbuyamazon extends ComputedFieldBase { /** * {@inheritdoc} */ public function ComputeValue(EntityInterface $host_entity, ComputedFieldDefinitionWithValuePluginInterface $computed_field_definition): array { if(!empty($host_entity->field_isbn10->value)) { $ISBN = $host_entity->field_isbn10->value; }else{ if(!empty($host_entity->field_amazon_asin->value)) { $ISBN = $host_entity->field_amazon_asin->value; }else{ $ISBN = ''; } } if(!empty($ISBN)) { $value = '<a href="http://www.amazon.com/gp/product/'.$ISBN.'" alt="" style="border:none !important; margin:0px !important;" />'; return [ 0 => [ 'value' => $value, 'format' => 'full_html', ], ]; } } }
I'm guessing it's somewhere in here I need to add a hook to make it seen in Views? I tried following the Drupal site information but nothing worked.
- 🇬🇧United Kingdom joachim
No, the hook goes in the .module file.
Again, again - USE MODULE BUILDER. It will put all the things in the right places for you.
BTW, I don't think this will work:
> if(!empty($host_entity->field_isbn10->value)) {
IIRC you need to use $entity->field->isEmpty()
- 🇬🇧United Kingdom joachim
An example of how to declare the field to Views in hook_views_data(), from my comment on 📌 Allow adding computed bundle fields in Views Fixed :
$data['node_field_data']['test_2981047_base'] = [ 'title' => t('Test computed base field 2981047'), 'entity field' => 'test_2981047_base', 'field' => [ 'id' => 'field', ], ]; $data['node_field_data']['test_2981047_bundle'] = [ 'title' => t('Test computed bundle field 2981047'), 'entity field' => 'test_2981047_bundle', 'field' => [ 'id' => 'field', ], ];
- 🇬🇧United Kingdom joachim
* "entity_types" = { * "entity_test" = {}, * },
Do you actually want to attach this field to the 'entity_test' entity type?
- 🇮🇹Italy MarcoPBazz
An example of how to declare the field to Views in hook_views_data(), from my comment on #2981047: Allow adding computed bundle fields in Views:
It's working form me (Drupal 9.5x + computed 4.0.0-alpha2) as I can show my computed field, but if I try to filter but I get "missing or broken handler for this element" as message.
Here's my code in my .views.inc file
function mymodule_views_data_alter(&$data) { $data['node_field_data']['myfield'] = [ 'title' => 'Myfield title', 'entity field' => 'myfield', 'field' => [ 'id' => 'field', ], 'filter' => [ 'title' => t('Myfield title'), 'field' => 'id', 'id' => 'myfield', ], ]; }
What am I missing?
- 🇬🇧United Kingdom joachim
You can't filter by a computed field, as there is no data in the database for SQL to query.
- 🇺🇸United States mlncn Minneapolis, MN, USA
Curious about the difference between joachim's example of how to declare the field to Views in hook_views_data() 💬 Access Computed Field in Views Active versus that in the change record associated with the same issue, Computed fields can now be displayed by Views → , which would seem to suggest something looking more like this:
/** * Implements hook_views_data_alter(). */ #[Hook('views_data_alter')] public function addComputedFieldChangedFields(&$data) { $data['node']['computed_example'] = [ 'title' => t('Computed field example'), 'field' => [ 'id' => 'field', 'default_formatter' => 'string', 'field_name' => 'computed_example', ], ]; } }
'node' instead of 'node_field_data', no 'entity field' line.
Confirmed that i can get it to show up using Joachim's approach; here is the full thing in the object-oriented hook implementation → available from Drupal 11.1 onward:
declare(strict_types = 1); namespace Drupal\example\Hook; use Drupal\Core\Hook\Attribute\Hook; class ViewsDataAlter { /** * Implements hook_views_data_alter(). */ #[Hook('views_data_alter')] public function addComputedFieldChangedFields(&$data) { $data['node_field_data']['computed_example'] = [ 'title' => t('Computed field example'), 'entity field' => 'computed_example', 'field' => [ 'id' => 'computed_example', ], ]; } }
However i am unable to test that it works beyond showing up in Views due to i think an unrelated error: 🐛 Call to undefined method Drupal\computed_field\Field\FieldStorageDefinition::getThirdPartySetting() Active
- 🇺🇸United States mlncn Minneapolis, MN, USA
With the code above and a
computed_example
field that is otherwise working, while i can add my field to a view it does not work, and indeed warns immediately:The handler for this item is broken or missing. The following details are available:
Installing the appropriate module may solve this issue. Otherwise, check to see if there is a module update available.
That is, Views knows my computed field has a broken or missing handler, but it cannot provide any details about it.
Suggestions?
- 🇬🇧United Kingdom joachim
> 'node' instead of 'node_field_data',
node is the base table, node_field_data is the field data table. It may be that one of those is the old way, I'm not sure. Check how Views declares config fields to views data.
> no 'entity field' line.
IIRC Views field handler plugins expect this property to be there, to tell it the name of the field.
> The handler for this item is broken or missing. The following details are available:
Can you debug to see what handler it's trying to use?
- 🇺🇸United States mlncn Minneapolis, MN, USA
Inside $this Drupal\views\Plugin\views\field\Broken, configuration, id = "computed_changed_shortterm_fields"
(In the report above i replaced "computed_changed_shortterm_fields" with "computed_example" but other than that it is identical.)
And before handlePluginNotFound, when PluginManagerBase does createInstance, the $plugin_id it has is "computed_changed_shortterm_fields" with $configuration:
id = "computed_changed_shortterm_fields"
group = TranslatableMarkup "String"
title = TranslatableMarkup "Computed changed short-term fields"
entity_type = "node"
entity field = "computed_changed_shortterm_fields"What is the plugin expected to be?
Again, the computed field itself with ID "computed_changed_shortterm_fields" is working, but including that code here for completeness:
<?php namespace Drupal\hw_household\Plugin\ComputedField; use Drupal\computed_field\Attribute\ComputedField; use Drupal\computed_field\Field\ComputedFieldDefinitionWithValuePluginInterface; use Drupal\computed_field\Plugin\ComputedField\ComputedFieldBase; use Drupal\computed_field\Plugin\ComputedField\SingleValueTrait; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Computed field which outputs short-term changed fields as a string. */ #[ComputedField( id: "hw_household_changed_shortterm_fields", label: new TranslatableMarkup("Changed short-term fields"), field_type: "string", )] class ChangedShortTermFields extends ComputedFieldBase { use SingleValueTrait; /** * {@inheritdoc} */ public function singleComputeValue(EntityInterface $entity, ComputedFieldDefinitionWithValuePluginInterface $computed_field_definition): mixed { $revision_id = \Drupal::service('revision_summary.compare_revisions')->latestRevisionIdWithChangedField($entity, 'field_date_stamp'); $fields = \Drupal::service('revision_summary.compare_revisions')->listChangedFields($entity, $revision_id); return implode(',', array_values($fields)); } }
(Relying on Revision Summary → module which i've contributed, though it turns out to really be using Diff module, remixed slightly.)
- 🇬🇧United Kingdom joachim
Is this bit:
> id = "computed_changed_shortterm_fields"
what you've declared to views data? 'id' is the ID of the Views field plugin to handle the field. And you've not defined that plugin. IIRC you can just use the plugin for the specific field type -- see the core issue for declaring bundle fields to views.
- 🇺🇸United States mlncn Minneapolis, MN, USA
I'm looking at the commit that allowed adding computed bundle fields in views via 📌 Allow adding computed bundle fields in Views Fixed and before i start trying things at random, are we talking for "id":
field
(looking in core, this is "EntityField" class at web/core/modules/views/src/Plugin/views/field/EntityField.php)computed_string_field
- … i don't think
computed_bundle_field
or something from core likestandard
,custom
, ormarkup
would apply, but maybe almost anything valid works?
- 🇬🇧United Kingdom joachim
> field (looking in core, this is "EntityField" class at web/core/modules/views/src/Plugin/views/field/EntityField.php)
That one.
computed_string_field and computed_bundle_field are not a views field plugin IDs, they are just the name of entity fields in a test.
- Merge request !20Add a views field handle rthat is NOT broken and will handle all computed fields for nodes → (Open) created by mlncn
- 🇺🇸United States mlncn Minneapolis, MN, USA
Sorry finally back to this and it is still bedeviling me:
#[Hook('views_data_alter')] public function addComputedFieldChangedFields(&$data) { $data['node_field_data']['hw_household_changed_shortterm_fields'] = [ 'title' => t('Computed changed short-term fields'), 'entity field' => 'field', 'field' => [ 'id' => 'computed_changed_shortterm_fields', ], ]; } }
Tried multiple variations for the field ID, including
node.household.computed_changed_shortterm_fields
andhousehold.computed_changed_shortterm_fields
.Before trying
computed_field.computed_field.node.household.computed_changed_shortterm_fields
, the full config file path for the field, and for all i know that would have worked, i dove into how views plugins work and understanding it from the perspective of writing a plugin that could be configured to show any (simple) computed field proved easy to understand for me, and the result is this merge request.It works great for my purposes and i would bet a good 80% of use cases.
Right now it returns the computed field for the entity with zero configuration that is theoretically possible for the view mode and bundle it was placed on. If anybody needs it, i am convinced i could figure out how to let a specific display configuration be chosen, or load those configuration options in the Views field settings, long before i could figure out how to do the cursed views data alter for a single custom computed field.
The views data alter that works for all computed fields in the merge request works great, and with the Views field plugin unlocks this for others without further custom code.
- 🇬🇧United Kingdom joachim
I don't understand this MR.
IIRC the problem is with declaring the fields to view. Why is a separate handler needed?
- 🇬🇧United Kingdom joachim
Yup, I just tried it, and you don't need a special field plugin. I don't understand what your MR does -- why are you selecting computed field plugins, which aren't even necessarily going to be attached to the entities shown in the view?
All you need for a config computed field is this:
/** * Implements hook_views_data_alter(). */ #[Hook('views_data_alter')] public function viewsDataAlter(array &$data) { // My computed field has the field machine name 'computed_computed_bundle_field'. This key is arbitrary, but using the field name keeps it tidy. $data['node_field_data']['computed_computed_bundle_field'] = [ 'title' => t('computed_computed_bundle_field field'), 'help' => t('Somecomputed_computed_bundle_fielder'), 'field' => [ // This is the field plugin to use for ANY entity field. 'id' => 'field', // I can't remember which of these is needed or if both are. 'entity field' => 'computed_computed_bundle_field', 'field_name' => 'computed_computed_bundle_field', ], ]; }
- 🇺🇸United States mlncn Minneapolis, MN, USA
Started documentation to save new adopters my trouble!
https://www.drupal.org/docs/extending-drupal/contributed-modules/contrib... →
That precise code does work, 'entity field' not needed.
Part of the problem for me in earlier attempts might have been not picking up that the field name needed is not the in-code ID of the computed field (plugin) but the machine name produced when you add the computed field to a content type / bundle via configuration. (Obviously i'm quite thick, but the fact that computed fields start with
computed_
rather thanfield_
and the tests usedtest_
helped obfuscate this.)My later attempts did not work either because i was misunderstanding 'entity field' to communicate the field plugin (`field`) and the
field
key to communicate only the field name; turns out what is essential is thatfield_name
andid
both be in thefield
array.As for my merge request: It does indeed allow you to use computed field without ever attaching it to the given content type. I don't consider that to be a deal-breaker, though, as it allows adding to the view without custom code, and computed fields themselves work the same way— you need to know when you configure them that they make sense for a particular content type (bundle), or it probably won't actually work. Being able to do computed fields in Views only without them being on the entity could be a minor feature in some use cases.
Currently the computed field views plugin would only work for computed fields with no configuration, as noted, though i think exposing computed field's configuration in the view field configuration could work the same as on regular bundle display field configuration.
- 🇬🇧United Kingdom joachim
> As for my merge request: It does indeed allow you to use computed field without ever attaching it to the given content type. I don't consider that to be a deal-breaker, though, as it allows adding to the view without custom code, and computed fields themselves work the same way
Yeah but that isn't at all how Views works. Views data declares fields (and which plugin they use), not plugins where you have to select the field in the UI.