Problem/Motivation

Right now, contact messages in core are created on the fly, rendered as an e-mail, sent and then dropped.

To make it more flexible, we should make message behave more like any other entity to support use cases like a contrib module switching the storage to log sent contact messages.

Proposed resolution

- Add a UUID field
- Add a langcode field which will be set to the current language automatically once that works
- "Save" the message, as we are now using the null storage, this will not do anything, but it will make it possible for a contrib module to switch out the storage and it should then just work. Right now, it would have to override the form to be able to call save itself.

Remaining tasks

User interface changes

API changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

corvus_ch’s picture

Assigned: Unassigned » corvus_ch
larowlan’s picture

Hi corvus_ch, any progress on this?
If not willing to pick it up

corvus_ch’s picture

Assigned: corvus_ch » Unassigned

No, not really. Thought I will be able to do it last weekend but…

So go ahead.

andypost’s picture

There's some tricks with message formatting in related issue.
+1 to add language field

larowlan’s picture

Assigned: Unassigned » larowlan

looking now

larowlan’s picture

Assigned: larowlan » Unassigned
Status: Active » Needs review
FileSize
11.5 KB

Works, to quote @berdir

so we just need a views fairy to write the views data generator and then we can provide a view of sent contact messages

but that's another issue

So this makes it possible to provide contact message storage, with a test implementation and tests to boot

Berdir’s picture

  1. +++ b/core/modules/contact/src/MessageForm.php
    @@ -254,5 +265,26 @@ public function save(array $form, array &$form_state) {
    +    // Make the message inherit the current content language unless specifically
    +    // set.
    +    if ($message->isNew()) {
    

    This doesn't seem to actually implement the "unless specifically set" part?

  2. +++ b/core/modules/contact/src/Tests/ContactStorageTest.php
    @@ -0,0 +1,73 @@
    + * Definition of Drupal\contact\Tests\ContactStorageTest.
    

    Contains ;)

  3. +++ b/core/modules/contact/src/Tests/ContactStorageTest.php
    @@ -0,0 +1,73 @@
    +    // Ensure that the contact form is shown without a category selection input.
    +    user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
    

    Did you copy that coment? Doesn't really make sense to me, especially because we no longer have a category selection input ;)

  4. +++ b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.module
    @@ -0,0 +1,40 @@
    +      ->setProvider('contact')
    

    Can we add a comment here why we set this explicitly?

  5. +++ b/core/modules/contact/tests/modules/contact_storage_test/src/ContactMessageStorage.php
    @@ -0,0 +1,29 @@
    +    // Marking the respective fields as NOT NULL makes the indexes more
    +    // performant.
    +    $schema['contact_message']['fields']['id']['not null'] = TRUE;
    

    Aren't the entity keys automatically marked as not null?

Otherwise, really nice! We can basically take that test module and start a contact_storage contrib project.

Would be nice to get feedback from @fago and @plach on the generic changes.

Berdir’s picture

@plach could probably also check if we need to change the install hook with #1498720: [meta] Make the entity storage system handle changes in the entity and field schema definitions, a real module probably also need uninstall?

larowlan’s picture

Addresses #7

Berdir’s picture

+++ b/core/modules/contact/src/MessageForm.php
@@ -279,7 +279,7 @@ protected function init(array &$form_state) {
     // set.
-    if ($message->isNew()) {
+    if ($message->isNew() && !$message->language()) {
       $language_content = \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);

language() automatically falls back to the default language, which always has to be set internally, so this doesn't work, you need to check the langcode field directly.

Re 5, did you verify that the key is NOT NULL'd correctly? I didn't, just think that's the case :)

larowlan’s picture

yeah, ContentEntitySchemaHandler::processIdentifierSchema() converts int to SERIAL which is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, so we're good there.

Fixes #10

Berdir’s picture

Assigned: Unassigned » plach

Usually works well to assign issues to @plach to get feedback from him, so let's try that :)

plach’s picture

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

Nice work :)

  1. +++ b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.install
    @@ -0,0 +1,22 @@
    +function contact_storage_test_install() {
    

    I don't think this is necessary and if it is we have a bug :)

    Entity schema should already be installed/uninstalled in the module handler.

  2. +++ b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.module
    @@ -0,0 +1,43 @@
    +      // Explicitly set this to 'contact' so that
    +      // ContentEntityDatabaseStorage::usesDedicatedTable() doesn't attempt to
    +      // put the ID in a dedicated table.
    +      ->setProvider('contact')
    

    This is weird, a base field should never end up in a dedicated table. This is surely taken care in #1498720: [meta] Make the entity storage system handle changes in the entity and field schema definitions, so if this necessary now, let's add a todo to remove this hack, also because the provider property is supposed to be set only by the Entity Manager.

Berdir’s picture

1. is I think necessary because we only install schema for entity types of the module that is currently installed, and contact has no storage then, so we don't install it, and when we install the test/storage module, but then we don't look at contact message again, because that's not provided by that module.

I assume that your changes issue might improve that, because it will detect a change after you install the storage module and will attempt to/allow to install the schema? we still might have to trigger it manually in the test somehow, not sure, did not look at your issue at all so far..

2. The problem is how we define if it's a base field or not. Right now, only fields added by the entity type itself are considered base fields (provider == entity type provider), and this is not. We kind of need the provider check there, or we'd keep expanding the node table with additional fields...

larowlan’s picture

Status: Needs work » Needs review

1. Yep it is needed because like berdir said, provide mismatch
2. Same, provider mismatch forced id into a dedicated table

So not sure if there is actually anything to do here - so bumping back to needs review

larowlan’s picture

plach’s picture

@berdir:

Spoke with @larowlan in IRC: both point make sense, but they should be fixed by #1498720: [meta] Make the entity storage system handle changes in the entity and field schema definitions, so let's add a todo about removing the related "hacks".

The problem is how we define if it's a base field or not

I'd say a base field is also any field defined through hook_entity_base_field_info() :)
-> Any field returned by EntityManagerInterface::getBaseFieldDefinitions().

larowlan’s picture

Added second @todo

plach’s picture

Looks RTBC to me, thanks.

tim-e’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/contact/src/MessageForm.php
    @@ -74,6 +76,15 @@ public function form(array $form, array &$form_state) {
    +    $language_configuration = \Drupal::moduleHandler()->invoke('language', 'get_default_configuration', array('contact_message', $message->getCategory()->id()));
    

    Can we inject?

  2. +++ b/core/modules/contact/src/MessageForm.php
    @@ -254,5 +265,26 @@ public function save(array $form, array &$form_state) {
    +      $language_content = \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
    

    Can we inject?

larowlan’s picture

Status: Needs work » Needs review
FileSize
5.91 KB
15.15 KB

Fixes #20 and a few other injection issues in MessageForm
there is no OO equiv of drupal_mail, drupal_set_message and user_cookie_save().
user_cookie_save() call can go when #749748: Contact, register and comment forms do not prefill with user info from browser is ready (its close) so added a todo and a note over there.

tim-e’s picture

Status: Needs review » Reviewed & tested by the community

Looks good

plach’s picture

Status: Reviewed & tested by the community » Needs work

The module handler is already available through setter injection in the EntityForm class...

larowlan’s picture

Status: Needs work » Needs review
FileSize
4.59 KB
14.97 KB

Fixes #23
We also have currentUser() from FormBase

plach’s picture

Status: Needs review » Reviewed & tested by the community

Looks good, thanks

andypost’s picture

Just a nitpick

+++ b/core/modules/contact/src/MessageForm.php
@@ -171,18 +192,19 @@ public function preview(array $form, array &$form_state) {
+    $user = $this->currentUser();

@@ -248,11 +270,32 @@ public function save(array $form, array &$form_state) {
+    if ($message->isPersonal() && $this->currentUser()->hasPermission('access user profiles')) {

second line could re-use $user too

larowlan’s picture

fixes 26

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs reroll
git ac https://www.drupal.org/files/issues/contact-storage-2289063.27.patch
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 14903  100 14903    0     0  14743      0  0:00:01  0:00:01 --:--:-- 15507
error: patch failed: core/modules/contact/src/Entity/Message.php:154
error: core/modules/contact/src/Entity/Message.php: patch does not apply
andypost’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs reroll
FileSize
14.54 KB

straight re-roll

Berdir’s picture

Was about to post the re-roll too.

There is only a small context change from setSettings() to setSetting().

@andypost mentioned that the issue this conflicted with (#1856562: Convert "Subject" and "Message" into Message base fields) needed some tricks re entity language, so maybe we can revert that now?

andypost’s picture

@Berdir Do you mean that hunk?

+++ b/core/modules/contact/src/MessageForm.php
@@ -71,9 +83,18 @@ public function form(array $form, array &$form_state) {
+    $language_configuration = $this->moduleHandler->invoke('language', 'get_default_configuration', array('contact_message', $message->getCategory()->id()));
+    $form['langcode'] = array(
...
+      '#default_value' => $message->getUntranslated()->language()->id,

@@ -186,7 +208,7 @@ public function save(array $form, array &$form_state) {
       // Send to the user in the user's preferred language.

Suppose we need @plach here

andypost’s picture

Also there's related issue #1938178: Contact module categories has not support language select
So probably we can drop that here

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 1793df6 and pushed to 8.x. Thanks!

  • alexpott committed 1793df6 on 8.x
    Issue #2289063 by larowlan, andypost | Berdir: Change contact message...

Status: Fixed » Closed (fixed)

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