Problem/Motivation

Please guide me what changes I need to do for make machine name working for content entity.

Currently in Drupal 8, a 'machine_name' widget is available only on primary identifiers of config entities, as content entities were expected to use serial entity identifiers only.

Some specific content entity types, however, are bordering to configuration and are therefore better identified by a string. Use cases include Core's new Workspace, Entityqueue's EntitySubqueue, FillPDF's FillPDF forms and the OP's contrib PET entity types.

This constitutes a regression from D7 where 'machine_name' fields were available as entity identifiers.

Proposed resolution

  1. Create a machine_name widget
  2. Allow 'string' type primary identifiers to specify the 'machine_name' widget in a content entity type's BaseFieldDefinition.
  3. Switch Core's Workspace entity to using a 'machine_name' widget on its 'string'-type id field replacing the current, ugly workaround.

Remaining tasks

Respond to #80
Fix the test failure
Review the CR
Review

User interface changes

Screeenshots in #2685749-114: Add a 'machine_name' widget for string field types with a UniqueField constraint from the patch in the same comment.

API changes

- none -

Data model changes

- none -

Original issue

I'm trying to port PET module, it uses custom entity to manage mail templates.
It has a machine name field, which I'm not able to make in Drupal 8. I checked code of Drupal 8 core, it uses machine name field for config type entities only, I did same way but it does not behave like machine name.

Please guide me what changes I need to do for make machine name working for content entity. Also let me know if this is an issue in core, I think the way fields are rendered in content entity might be the reason.

Current code can be seen here http://cgit.drupalcode.org/pet/tree/.

CommentFileSizeAuthor
#135 interdiff_130_135.txt994 bytesleymannx
#135 machine-name-widget-2685749-135.patch33.72 KBleymannx
#131 machine-name-widget-2685749-130.patch33.71 KBa.dmitriiev
#129 machine-name-widget-2685749-129.patch33.72 KBa.dmitriiev
#128 reroll_diff_116_128.txt5.19 KBa.dmitriiev
#128 machine-name-widget-2685749-128.patch33.69 KBa.dmitriiev
#127 drupal-9-5x-machine-name-widget-2685749-127.patch14.15 KBtgoeg
#116 drupal-10-1x-machine-name-widget-2685749-116.patch34.23 KBjames.williams
#116 drupal-9-5x-machine-name-widget-2685749-116.patch34.25 KBjames.williams
#116 interdiff-2685749-114-116.txt1.41 KBjames.williams
#114 drupal-10-1x-machine-name-widget-2685749-114.patch34.22 KBjames.williams
#114 drupal-9-5x-machine-name-widget-2685749-114.patch34.24 KBjames.williams
#114 interdiff-2685749-106-114.txt1.62 KBjames.williams
#114 widget-settings-expanded.png106.62 KBjames.williams
#114 widget-settings-collapsed.png55.12 KBjames.williams
#114 machine-name-widget-editing.png40.96 KBjames.williams
#114 machine-name-widget.png20.55 KBjames.williams
#113 reroll_diff_106-112.txt27.12 KBAkram Khan
#112 2685749-112.patch14.29 KBAkram Khan
#106 reroll_diff_2685749_101-106.txt2.7 KBankithashetty
#106 2685749-106.patch34.22 KBankithashetty
#103 2685749-103.patch33.46 KBSupreetam09
#102 2685749-D9.2.x-102.patch13.75 KBSupreetam09
#101 2685749-101.patch33.77 KBcharginghawk
#100 interdiff-100.txt1.32 KBcharginghawk
#100 2685749-100.patch33.77 KBcharginghawk
#98 2685749-98.patch13.11 KBcharginghawk
#97 2685749-97.patch34.66 KBSupreetam09
#96 2685749-96.patch34.66 KBSupreetam09
#94 2685749-94.patch32.86 KBweseze
#92 2685749-92.patch33.77 KBPasqualle
#91 interdiff-2685749-91.txt3.27 KBPasqualle
#91 2685749-91.patch33.71 KBPasqualle
#85 2685749-85.patch32.99 KBMarcin Maruszewski
#83 2685749-83.patch32.58 KBMarcin Maruszewski
#82 2685749-82.patch13.73 KBMarcin Maruszewski
#79 interdiff-79.txt644 bytesamateescu
#79 2685749-79.patch32.83 KBamateescu
#73 interdiff-73.txt6.89 KBamateescu
#73 2685749-73.patch32.82 KBamateescu
#68 interdiff-68.txt2.85 KBamateescu
#68 2685749-68.patch31.77 KBamateescu
#64 interdiff-64.txt2.05 KBamateescu
#64 2685749-64.patch31.55 KBamateescu
#56 interdiff-56.txt2.02 KBamateescu
#56 2685749-56.patch30.89 KBamateescu
#55 interdiff-55.txt7.25 KBamateescu
#55 2685749-55.patch30.8 KBamateescu
#38 interdiff-38.txt885 bytesamateescu
#38 2685749-38.patch29.55 KBamateescu
#33 interdiff-33.txt2.26 KBamateescu
#33 2685749-33.patch29.55 KBamateescu
#31 interdiff-31.txt4.64 KBamateescu
#31 2685749-31.patch27.29 KBamateescu
#26 interdiff.txt2.11 KBamateescu
#26 2685749-26.patch22.65 KBamateescu
#17 interdiff-17.txt18.9 KBamateescu
#17 2685749-17.patch22.55 KBamateescu
#11 2685749-11.patch21.12 KBamateescu
#10 2685749-wip.patch7.17 KBamateescu

Issue fork drupal-2685749

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Sharique created an issue. See original summary.

swentel’s picture

Why do you need a machine name for a content entity ? You already have the an id and uuid ?

Sharique’s picture

@swentel, it was there in D7 version, so want to keep that as it is. Can you tell me why machine name field is not working for content entity type?
I'm also thinking about dropping machine name field if not able to make it work is correctly.

swentel’s picture

Well, most content entities don't have machine name field as most of them use a serial field and a uuid. That's already unique enough to be fair.

amateescu’s picture

Title: Machine name field for content type entity » Add a 'machine name' widget for text/string field types
Version: 8.0.5 » 8.2.x-dev
Category: Support request » Feature request
Issue tags: -machine name +Entity system

The entity_subqueue content entity type from the Entityqueue module also needs a 'machine name' field widget, so I think it's worth giving this a try :)

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

timmillwood’s picture

amateescu’s picture

Here's an initial WIP patch which shows the complexity of this widget. And there are two separate issues that need to be fixed as well, as can be seen in the first two hunks from the patch.

Not sending this patch to the testbot because it's useless at the moment.

amateescu’s picture

Category: Feature request » Task
Status: Active » Needs review
FileSize
21.12 KB

I finally managed to get this working. It was a lot trickier than I expected but I'm pretty happy with its behavior now and we have complete test coverage as well :)

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community

Looks very awesome!

I can imagine it was tricky, but it's quite an elegant solution.

Small nitpick which can be fixed on commit, if it's an issue at all:

+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
@@ -0,0 +1,196 @@
+    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
+
+    $this->entityFieldManager = $entity_field_manager;
+    $this->elementInfo = $element_info;

I wouldn't usually expect a blank line here.

amateescu’s picture

Oh, I always leave a blank line in the constructor between the parent call and local variable assignments, I like the code to have enough "breathing room" :)

The last submitted patch, 10: 2685749-wip.patch, failed testing. View results

larowlan’s picture

Status: Reviewed & tested by the community » Needs review
  1. +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
    @@ -0,0 +1,196 @@
    + *   field_types = {
    + *     "string"
    + *   }
    

    I think this should be no ui. Pretty sure the UX/product team won't want to present 'regex' to users. Given we're going to use it on base fields for workspaces - I think that would be fine. @Sharique - can you confirm that would suit PET module too?

  2. +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
    @@ -0,0 +1,196 @@
    +class MachineNameWidget extends WidgetBase implements ContainerFactoryPluginInterface {
    

    Does this need to provide a config dependency on the field it references?

  3. +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
    @@ -0,0 +1,196 @@
    +        'exists' => $this->getSetting('exists'),
    

    Is there a test for this?

+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
@@ -0,0 +1,196 @@
+ *     "string"

I really think this should be its own Field Type that has a constraint to validate unique. We're validating unique in the form layer, but not for things like REST.

amateescu’s picture

Assigned: Unassigned » amateescu
Status: Needs review » Needs work

Thanks @larowlan for a great review! I've started to work on your points and I'll post a detailed reply tomorrow.

amateescu’s picture

Title: Add a 'machine name' widget for text/string field types » [PP-1] Add a 'machine name' widget for text/string field types
Assigned: amateescu » Unassigned
Status: Needs work » Postponed
FileSize
22.55 KB
18.9 KB

Ok, here it is :)

Re #15:

1. Totally agreed there, it's exactly what I did initially only to find out that the "no ui" concept does not exist for widgets and formatters, only for field types. So we can do the next best thing and use isApplicable() to make this widget available only to entity ID fields. This is actually the 99% use case and it satisfies all the modules that need this widget so far: Workspaces, Entityqueue and the PET module from the IS.

2. It doesn't need to declare a config dependency because the source field has to be configured in the form display if it wants to be available as a source and the entity form display config entity already depends on all its components (aka. configured fields).

3. There is now :)

4. Sadly, this can not really be its own field type because, for example, @alexpott asked in #2885469: Regression: manually setting the ID field for newly-created content entities is not possible anymore (public follow-up to SA-2017-002) to allow setting an entity ID explicitly only for string ID fields. And we also have an existing issue to deal with this in REST: #2870649: REST should respond with a 409 for a POST request to an existing entity

Since we're limiting this widget to be available only to ID fields, we're effectively blocked on #2885469: Regression: manually setting the ID field for newly-created content entities is not possible anymore (public follow-up to SA-2017-002) for now because the tests will fail without that patch.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

amateescu’s picture

Title: [PP-1] Add a 'machine name' widget for text/string field types » Add a 'machine name' widget for text/string field types
Status: Postponed » Needs review

#2885469: Regression: manually setting the ID field for newly-created content entities is not possible anymore (public follow-up to SA-2017-002) is in, so we can unpostpone this one. It would allow us to clean up some form code in the workspaces module :)

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community

The patch from #17 looks good.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 17: 2685749-17.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Reviewed & tested by the community
alexpott’s picture

I think the work around in #17 to not having no ui available looks good. Given it does not does do exactly what @larowlan asked for in #15 I'm going to ping @larowlan but I'm +1 on commit.

larowlan’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
    @@ -193,4 +190,35 @@ public static function processMachineNameSource($element, FormStateInterface $fo
    +      ->condition(reset($element['#array_parents']), $value, '=')
    

    I don't think this will work with IEF - so we need something less brittle here.

  2. +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
    @@ -193,4 +190,35 @@ public static function processMachineNameSource($element, FormStateInterface $fo
    +    // This widget is available only to entity identifier fields.
    

    This is a reasonable compromise

amateescu’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
22.65 KB
2.11 KB

Re #25.1: That's right and also easy to fix: we can just put all the info we need in the widget's form element.

Tested with IEF and everything works perfectly :)

larowlan’s picture

I really think this should be its own Field Type that has a constraint to validate unique. We're validating unique in the form layer, but not for things like REST.

I think this comment still stands?

amateescu’s picture

@larowlan, I answered that point in #17.4.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 26: 2685749-26.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Reviewed & tested by the community

Testbot was acting up.

amateescu’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
27.29 KB
4.64 KB

Actually, now that the workspace module has been committed, we have the first use case for this widget in core!

The interdiff shows what kind of ugly code can be removed :)

Status: Needs review » Needs work

The last submitted patch, 31: 2685749-31.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Needs review
FileSize
29.55 KB
2.26 KB

A couple more tests needed to be updated.

amateescu’s picture

Status: Needs review » Reviewed & tested by the community

#31 was a simple change to remove the current custom code from from Workspaces to use the new widget, which also brings an indirect level of test coverage on top of the existing dedicated one, so I think it's ok to move this back to RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 33: 2685749-33.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Reviewed & tested by the community

Random fail.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 33: 2685749-33.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
29.55 KB
885 bytes

Rerolled.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 38: 2685749-38.patch, failed testing. View results

darvanen’s picture

Status: Needs work » Reviewed & tested by the community

As this is passing on 8.7 and it likely won't make it into 8.6, I think it should be RTBC as per #34

ndf’s picture

#15 and #27 are still open: larowlan asked for an additional unique FieldType.

The current patch adds a FieldWidget (in itself already an improvement).

Could we RTBC and then create a follow-up for the unique FieldType?

amateescu’s picture

@ndf, I replied to #15 and #27, see #17.4. And we're already RTBC :)

ndf’s picture

@amateescu Sorry I missed 17.4
Then RBTC from me too.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record, +Needs issue summary update

Still think this patch looks good. Realised though that the issue summary is out-of-date and there is no change record. Needs work for those things.

Pancho’s picture

Title: Add a 'machine name' widget for text/string field types » Add a 'machine_name' widget for string-type entity identifiers
Issue summary: View changes
Issue tags: -Needs issue summary update

Updated issue summary.

amateescu’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs change record

Thanks, @Pancho! Here's a CR too: https://www.drupal.org/node/3028311

Pancho’s picture

Issue summary: View changes

Further refined issue summary.

edit: Oops, now we have two change records. We might want to combine the best of both.

amateescu’s picture

@Pancho, oops indeed :) I added the usage example from your CR to the one linked in #47.

Pancho’s picture

Issue summary: View changes

added another followup task

Pancho’s picture

Think this should actually be postponed to that other issue which is creating a whole new separate ‘machine_type’ field type.

amateescu’s picture

@Pancho, as far as I see, that issue introduces a 'machine_name' config data type, while this one is about providing a field widget for content entity types, so they're not related at all regarding their functionality.

Pancho’s picture

@amateescu You're completely right, sorry. Remains RTBC.

dww’s picture

+  public static function isApplicable(FieldDefinitionInterface $field_definition) {
+    // This widget is available only to entity identifier fields.
+    $entity_type = \Drupal::entityTypeManager()->getDefinition($field_definition->getTargetEntityTypeId());
+
+    return $field_definition->getName() === $entity_type->getKey('id');
+  }

Do we need to enforce this? What if I want a 'machine_name' widget on some other kind of field? I might want all the same behavior of the machine name widget for giving machine names to some other kind of content on a site. E.g. I need my projects to have a machine name, even though they're nodes that officially have integer IDs. Why can't I define my own string field for this and reuse the 'machine name' widget?

amateescu’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
30.8 KB
7.25 KB

@dww, that was my attempt to resolve @larowlan's request from #15 (last paragraph), but now that I think about it again, maybe it's better to enforce that the field definition has a UniqueField constraint rather than being the entity identifier.

amateescu’s picture

A couple of self-review fixes :)

Pancho’s picture

Updated change record. I only added a sentence in the end, because the widget will still primarily be there for string-type identifiers.

This one now depends on #3027745: UniqueFieldConstraint doesn't work for entities with string IDs being committed first to ensure the machine_name really is unique, am I right? In that case, we should actually see a failing test here.

amateescu’s picture

Title: Add a 'machine_name' widget for string-type entity identifiers » Add a 'machine_name' widget for string field types with a UniqueField constraint

Better title for the new approach in #55.

The last submitted patch, 55: 2685749-55.patch, failed testing. View results

amateescu’s picture

This one now depends on #3027745: UniqueFieldConstraint doesn't work for entities with string IDs being committed first to ensure the machine_name really is unique, am I right? In that case, we should actually see a failing test here.

Not necessarily :) There are two use cases for this widget:

1) for the identifier field of an entity type with string IDs
2) for a string field with a UniqueField constraint, on an entity type with either integer or string IDs

The first case is what we're doing for the workspace entity type, and it works just fine. The second case is the "problematic" one, but only in the case where the entity type uses a string ID.

So I'm not sure whether there's a hard dependency, that issue is a bug that needs to be fixed regardless of this new widget.

amateescu’s picture

That issue was just committed, does anyone want to RTBC this one? :)

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

jhedstrom’s picture

This looks good to me. Just some tiny nits below and then I think it's RTBC.

  1. +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceTest.php
    @@ -52,23 +52,24 @@ public function setUp() {
    -    $page = $this->getSession()->getPage();
    
    +++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/Field/Widget/MachineNameWidgetTest.php
    @@ -0,0 +1,228 @@
    +   * Node is required because the machine name callback checks for the
    +   * "access content" permission.
    

    I'd hoped that machine names wouldn't always require node, so in digging I found that actually the `access content` permission is defined by the system module, so either just that module can be installed, or this comment can be updated.

  2. +++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/Field/Widget/MachineNameWidgetTest.php
    @@ -0,0 +1,228 @@
    +    entity_get_form_display('entity_test_string_id', 'entity_test_string_id', 'default')
    ...
    +    entity_get_form_display('entity_test_string_id', 'entity_test_string_id', 'default')
    ...
    +    entity_get_form_display('entity_test_string_id', 'entity_test_string_id', 'default')
    ...
    +    entity_get_form_display('entity_test_string_id', 'entity_test_string_id', 'default')
    

    Should new usages of deprecated functions be added?

amateescu’s picture

@jhedstrom, thanks for the review!

Re #63:

1. Very good point, we can clean that up and just assign the access content permission to the test user because the system module is installed by default.

2. Those functions are not really deprecated because they don't have any replacements. That problem will be fixed in #2367933: Move entity_get_(form_)display() to the entity display repository :)

jhedstrom’s picture

Status: Needs review » Reviewed & tested by the community

This looks good to me.

Those functions are not really deprecated because they don't have any replacements.

Good to know! I'd always thought the recommended replacement in the deprecation notice was incomplete compared to the old functionality :)

Pancho’s picture

Issue summary: View changes

Added one more example. These are all borderline-configuration ContentEntityTypes.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 64: 2685749-64.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
31.77 KB
2.85 KB

Fixed usages of entity_get_form_display() which is properly deprecated now.

larowlan’s picture

Status: Reviewed & tested by the community » Needs review
  1. +++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
    @@ -170,8 +170,15 @@ public function buildForm(FieldableEntityInterface $entity, array &$form, FormSt
    +    // Sort the components by their weight in order to allow a form element from
    +    // a widget to depend on the processed elements of another form element from
    +    // another widget. For example, the 'machine_name' widget needs the
    +    // processed '#id' property of its source field.
    +    $components = $this->getComponents();
    +    uasort($components, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
    +
         // Let each widget generate the form elements.
    -    foreach ($this->getComponents() as $name => $options) {
    +    foreach ($components as $name => $options) {
    

    Note to other reviewers, this happens in the machine name element plugin (not in the widget)

  2. +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
    @@ -0,0 +1,209 @@
    +    foreach (array_intersect_key($available_fields, $displayed_fields) as $field_name => $field) {
    +      // The source field can only be another string field.
    +      if ($field->getType() === 'string' && $field->getName() !== $this->fieldDefinition->getName()) {
    +        $options[$field_name] = $field->getLabel();
    +      }
    +    }
    

    We could also limit these by weight in the display here right?

    I.e we're already filtering out items that aren't enabled, but could we also inspect their weight relative to the weight of this item?

  3. +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
    @@ -28,7 +28,7 @@ public function validate($items, Constraint $constraint) {
    +    if (isset($entity_id) && !$entity->isNew()) {
    

    if the entity is new, then why would it have a value in the database that would impact the query?

    i.e if the entity is new, adding a <> against its ID won't return any results right? Because its not saved yet.

    I'm not convinced we need this change - can you elaborate on why it was needed?

andypost’s picture

+++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
@@ -170,8 +170,15 @@ public function buildForm(FieldableEntityInterface $entity, array &$form, FormSt
+    uasort($components, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);

Only nit SortArray:class

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

joachim’s picture

Status: Needs review » Needs work

Looks good overall.

Just one small thing:

+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
@@ -0,0 +1,209 @@
+    // This widget is only available to fields that have a 'UniqueField'
+    // constraint.

This is a detail that could do to be also mentioned in the class docs, for DX. Imagine a developer trying to figure out why this widget doesn't show in the UI.

amateescu’s picture

Thanks everyone for the reviews :)

Re #69:

2. That's a good idea! Done and updated the test coverage to take this new behavior into account.

3. That change fixes a bug introduced in #3027745: UniqueFieldConstraint doesn't work for entities with string IDs, which didn't take into account that the UniqueField constraint could be set on the ID field itself. In that case, when adding a new entity with a string ID, the entity ID is set by the form (this doesn't happen for entities with integer IDs), so $entity->id() will never be NULL, which essentially makes the query ignore other pre-existing entities which have the same ID as the newly created one.

I've updated the comment and the code to make it more clear when we need to add that condition to the query.

#70: heh, fixed.

#72: good point, fixed as well.

andypost’s picture

Related issues: +#2091871: Add an ConfigEntityForm with an exists() method
amateescu’s picture

Status: Needs review » Reviewed & tested by the community

Setting back to RTBC because all the reviews were addressed.

japerry’s picture

This is looking good. In prep for this getting into core, I've rolled a 2.x branch of the machine_name_widget module that contains most of this code.
Some of the core features like checking uniqueness isn't there, but the basic ability to add machine names is.

https://www.drupal.org/project/machine_name_widget/releases/8.x-2.0-alpha1

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

xjm’s picture

Status: Reviewed & tested by the community » Needs review

The 9.1.x tests failed: https://www.drupal.org/pift-ci-job/1672843

I requeued it to be sure, but this issue may need a different patch for 9.x. Thanks!

amateescu’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
32.83 KB
644 bytes

Fixed that :)

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
    @@ -170,8 +171,15 @@ public function buildForm(FieldableEntityInterface $entity, array &$form, FormSt
    +    // Sort the components by their weight in order to allow a form element from
    +    // a widget to depend on the processed elements of another form element from
    +    // another widget. For example, the 'machine_name' widget needs the
    +    // processed '#id' property of its source field.
    +    $components = $this->getComponents();
    +    uasort($components, [SortArray::class, 'sortByWeightElement']);
    +
         // Let each widget generate the form elements.
    -    foreach ($this->getComponents() as $name => $options) {
    +    foreach ($components as $name => $options) {
    

    Does this mean that you can break the form by re-ordering the fields in the UI? It looks like it. We prevent you from choosing an impossible source field but can you re-order the fields after doing this.

  2. +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
    @@ -25,11 +25,10 @@ public function validate($items, Constraint $constraint) {
    -    $entity_id = $entity->id();
    -    // Using isset() instead of !empty() as 0 and '0' are valid ID values for
    -    // entity types using string IDs.
    -    if (isset($entity_id)) {
    -      $query->condition($id_key, $entity_id, '<>');
    +    // If the entity already exists in the storage, ensure that we don't compare
    +    // the field value with the pre-existing one.
    +    if (!$entity->isNew()) {
    +      $query->condition($id_key, $entity->id(), '<>');
         }
    

    Should these changes have test coverage in \Drupal\KernelTests\Core\Validation\UniqueFieldConstraintTest?

  3. +++ b/core/modules/workspaces/tests/src/Functional/WorkspaceTestUtilities.php
    @@ -57,13 +57,11 @@ protected function getOneEntityByLabel($type, $label) {
    -    $this->getSession()->getPage()->hasContent("$label ($id)");
    

    Should we at least assert a 200?

vbory’s picture

Can anybody explain why we use closure function in MachineNameWidget class?

'exists' => function () {
  return FALSE;
}

The Drupal\Component\Serialization\PhpSerialize can't serialize the MachineNameWidget class, because we have closure function.

Marcin Maruszewski’s picture

I have the same issue as vbory said in #81. The issue occurs while I was trying to create a new entity_reference item via inline_entity_form (complex widget).

I copied patch from #79 but removed this Closure. I hope it's gonna work too.

Marcin Maruszewski’s picture

FileSize
32.58 KB

Small fix for #82

Neograph734’s picture

Status: Needs work » Needs review
Marcin Maruszewski’s picture

Apologies for last two, not working patches. I spend some time, check where this Closure is used and find some solution.

Like @bvory noticed a Closure can't be serialized. But as it's described in docs https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21... the "exists" parameter should be a callable.

For this issue, I have a workaround. We can create method witch always return false and set it as a callback. This solution is working for me, but I'm not sure is it a good solution. Maybe we just should check "MachineName::validateMachineName" does exist callback function is set and leave it empty in MachineNameWidget.

Neograph734’s picture

I believe the issues @alexpott mentioned in #80 are still not resolved. So this still needs work?

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

gaurav_manerkar’s picture

Hello, Any update?

Daniel Kulbe’s picture

Working properly.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Pasqualle’s picture

reroll
added option "Standalone" to the widget settings. see api.drupal.org

Pasqualle’s picture

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

weseze’s picture

Patch from #92 wasn't working for us against 9.3.0.
So rerolled patch attached.

Akhildev.cs’s picture

hi, I tried, the rerolled patch #94 is not working for me.

Supreetam09’s picture

Patch #73 for D8.9.x is partially working. Throwing issue "Serialization of Closure is not allowed in Serialize()" when trying to modify a custom content block having paragraph type entity reference field. Creating new patch here.
Note: This is for D8.9.x only.

Supreetam09’s picture

charginghawk’s picture

Rerolling the 94 patch for 9.3.0 / 9.3.x.

Status: Needs review » Needs work

The last submitted patch, 98: 2685749-98.patch, failed testing. View results

charginghawk’s picture

Hm, rerolling the #92 patch for 9.3.0 / 9.3.x!

charginghawk’s picture

Fixing this:

FILE: /Users/chart/Projects/drupal/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 33 | ERROR | [x] Expected "\Drupal\Core\Entity\EntityFieldManagerInterface" but found "\Drupal\Core\Entity\EntityFieldManagerInterface;" for @var tag in member variable comment
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Supreetam09’s picture

Adding patch for specific 9.2.x Drupal core version following #101

Supreetam09’s picture

Ignore the above ^^ patch in #102 as I mistakenly did not add the untracked files.
Adding new patch for D9.2.x here.

voleger’s picture

Status: Needs review » Needs work
FILE: /var/www/html/core/modules/workspaces/src/Form/WorkspaceForm.php
----------------------------------------------------------------------
FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE
----------------------------------------------------------------------
 7 | WARNING | [x] Unused use statement

PHPCS is not happy

Pasqualle’s picture

The field widget should have "Textfield size" option.

ankithashetty’s picture

Status: Needs work » Needs review
FileSize
34.22 KB
2.7 KB

Addressed #105 in patch #101, please review.

Thanks!

jibran’s picture

Issue tags: +Needs screenshots

I think we need a usability review on this ticket before we tag it with "usability review" let's add all the screenshots for the widget and its setting to the IS.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

sandeep_jangra’s picture

Assigned: Unassigned » sandeep_jangra

I'm working on this.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

nod_’s picture

Assigned: sandeep_jangra » Unassigned
Status: Needs review » Needs work

I'm guessing this won't make it to 9.x, so a D10 patch would be necessary (#106 seems to be applying well enough on 10.1)

In The D10 version

+++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
@@ -173,8 +174,15 @@ public function buildForm(FieldableEntityInterface $entity, array &$form, FormSt
+    uasort($components, [SortArray::class, 'sortByWeightElement']);

I think according to #3259716: Replace usages of static::class . '::methodName' to first-class callable syntax static::method(...) this should be: uasort($components, SortArray::sortByWeightElement(...));

setting to NW for the screenshots at least

Akram Khan’s picture

Creating patch for 10.1.x and address #111

Akram Khan’s picture

FileSize
27.12 KB

attached reroll file

james.williams’s picture

Patch #112 (a re-roll of #106) omitted the new files that were being added in #106. (And the interdiff for it, posted in #113, therefore showed those files removed.)

Here's a replacement patch that includes the new files. This is a re-roll of #106, including the suggestion from #111 to use the new callable syntax. I include an interdiff of this vs #106. Drupal 9.5 sites may not support the callable syntax new to PHP 8.1, so I include a patch for D9.5.x too (without interdiff - I've just retained the previous uasort($components, [SortArray::class, 'sortByWeightElement']); line).

I've also included some screenshots of the new widget settings (collapsed+expanded), and the widget itself in action (before+after clicking the 'edit' link). I trust those might be enough screenshots? Since this is new functionality, I presume we don't need screenshots of how it looked before the change? More can be made if needed of course!

Status: Needs review » Needs work
james.williams’s picture

Fixed the test failure which was due to case sensitivity. (To my surprise!)

I also spotted that the widget's isApplicable() relies on the options having been set when adding the constraint. I don't see anywhere documented that requires that; so I've replaced an isset() for an array_key_exists() so that calls like ->addConstraint('UniqueField') will work rather than requiring an empty second parameter ->addConstraint('UniqueField', []). (There are instances in core of other constraints being added without setting the options parameter, such as in \Drupal\Core\Entity\EntityType::__construct().)

Status: Needs review » Needs work
james.williams’s picture

Status: Needs work » Needs review

Previous test failure was for a hopefully unrelated Ckeditor5 test. Tests all passed on a retest!

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs issue summary update
james.williams’s picture

That issue talks about using a "duplicate ID" - if that's talking about a field with a unique value constraint, it could actually be solved by the work that has now been done here. All that would be needed (on top of this work) is for the constraint to be added to that field, I believe.

Or it's talking about using the entity ID field itself, rather than a field using a machine name constraint/field/widget. Which would be related, but I don't think blocks this issue at all. It might even still be able to make use of it in the same way - by simply adding the constraint to the appropriate entity ID field.

So I could be wrong, but I'm updating the IS based on that belief that it's a related issue, not a blocker to this one. Correct me if I am indeed wrong!

smustgrave’s picture

Status: Needs review » Needs work

Thanks for updating that! This one may need more eyes but noticed the change record was written for D8 and this probably will only make it in 10.2. So if that could be updated.

james.williams’s picture

Status: Needs work » Needs review

Ok; updated the change record to now target 10.2.0.

10.2.x-dev isn’t an option for the issue metadata here though. I guess we just wait to get it into that or main or whatever becomes available?

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

So tested by enabling entity_test module and going to entity_test_string_id/structure/entity_test_string_id/form-display
Verifying the ID field can switch between textfield and machine_name.

Verified that regular Text(only) field doesn't get machine_widget.

Not sure how other to test this one. But lets get into committer eyes. May be easier to get into 10.2 early

quietone’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Needs work

Thanks to everyone here for moving this 7 year old issue along!

I triaged this and updated the remaining tasks accordingly. Here are the details.

The issue summary states that there are no user interface changes but this is adding a new widget. And in #107, screenshots were asked for. I eventually found them in #144. @james.williams, thanks for making them. It really helps reviewers/committers if the screenshots are in the IS or a link to the comment so they can be found. Also, with a note saying which patch/MR version they were made with. (I just added it)

There were many questions raised in the reviews, that is good to see and read. However, #80 has not been answered. I have added that to the remaining tasks.

#124 says "Not sure how other to test this one. But lets get into committer eyes." Instead, before setting to RTBC ask in #contribute for first. An issue that is Reviewed & tested by the community ("RTBC") should not have any questions unanswered, it should be ready for commit.

I read the CR and made changes to use plain English. There should be no changes to the content but someone should check that. I am adding a review of the CR to the remaining tasks. The CR mentions the benefits to site builders but site builder' is not selected in the 'Impacts'. Should it be? The CR should also include a screenshot. These two look the most informative,

https://www.drupal.org/files/issues/2023-05-16/widget-settings-collapsed...
https://www.drupal.org/files/issues/2023-05-16/widget-settings-expanded.png

The latest patch is failing tests and is on 10.1x. This needs to be on 11.x with passing tests. Setting to NW.

I am updating credit, always a challenge on issues with > 100 comments.

A reminder to all that when making a patch, an interdiff or diff is needed. There are instructions for creating an interdiff. If you think a diff is not needed, add a comment stating why.

ankondrat4’s picture

Hello.

You can try using this module https://www.drupal.org/project/machine_name_widget

tgoeg’s picture

The patch in #2685749-116: Add a 'machine_name' widget for string field types with a UniqueField constraint for Drupal 9.5 is broken.
It adds two unnecessary files
core/b/core/tests/Drupal/FunctionalJavascriptTests/Core/Field/Widget/MachineNameWidgetTest.php
core/b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/MachineNameWidget.php

They do not differ from the ones at the correct path, so I just removed them.

It should look like the one attached.

a.dmitriiev’s picture

Re-roll of the patch from 116 for 11.x. Fixing the testPublishWorkspace as well.

a.dmitriiev’s picture

Fix failure of custom commands

Anybody’s picture

Status: Needs review » Needs work

Thanks @a.dmitriiev! :) Still 1 failing test left.

Could you perhaps use a MR to make reviews easier?

a.dmitriiev’s picture

Status: Needs work » Needs review
FileSize
33.71 KB

Here is the patch the same as MR. I figured out the failing test: after changing machine name to client side only, the trailing replace char is also removed. I hope now the tests will pass.

a.dmitriiev’s picture

Status: Needs review » Needs work

Still the same test fails. However, the expected string is exactly the same as widget produces in admin UI when checking the same thing manually.

leymannx’s picture

leymannx’s picture

Looks like the machine name is wrong. When I add a new field anywhere in Drupal, naming it Test value !0-9@, the machine name gets auto-created as field_test_value_0_9_ with an underscore (_) at the end.

leymannx’s picture

Which would be strange, though, as the machine name test says also says Test value !0-9@ translates to test_value_0_9: https://git.drupalcode.org/project/drupal/-/blob/11.x/core/tests/Drupal/... 🧐

leymannx changed the visibility of the branch 11.x to hidden.

leymannx’s picture

Okay, I reverted the commit. That wasn't it.

leymannx’s picture

Okay, I found a way to output the machine name value from the field and it's a completely different value than the one that's expected: jvfavt8z == test_value_0_9 wich of course is false. Same can be seen in the test artefacts.

It's also the same what I experienced after I put $settings['extension_discovery_scan_tests'] = TRUE; into my settings.php and enabled the entity_test module. I opened URL /entity_test_string_id/add and it always contained some random name in the name field and the machine name field was always pre-filled with this machine name. When I changed the name, the machine name didn't change accordingly. It always stayed the same.

(It also looks really different from all other machine name elements I know in Drupal.)

By the name of Dries I couldn't find where this arbitrary name value was coming from. On every page load it was a different one. I also don't understand why all other asserts succeed and only this one doesn't.

Does anybody here have an idea why when accessing /entity_test_string_id/add the name is always pre-filled with a random value? Where does it come from?