Problem/Motivation

In #3197482: Update Drupal 10 to depend on Symfony 5.4 (as a stepping stone to Symfony 6, for deprecation checking support), the Symfony 5.4 update is failing with this:

Method "Symfony\Contracts\Translation\TranslatorInterface::trans()" might add "string" as a native return type declaration in the future. Do the same in implementation "Drupal\Core\Validation\DrupalTranslator" now to avoid errors or add an explicit @return annotation to suppress this message.

Method "Symfony\Contracts\Translation\TranslatorInterface::getLocale()" might add "string" as a native return type declaration in the future. Do the same in implementation "Drupal\Core\Validation\DrupalTranslator" now to avoid errors or add an explicit @return annotation to suppress this message.

Proposed resolution

Revert #3231683: [Symfony 6] A number of methods of the class Drupal\Core\TypedData\Validation\ExecutionContext are considered internal and Drupal should not override them. to use our own TranslatorInterface instead.

We tried to ague to make Symfony more extensible / consistent in this regard so we don't need to do this, but that was not accepted at https://github.com/symfony/symfony/pull/44911

Remaining tasks

Review. Commit.

User interface changes

API changes

See release notes snippet.

Data model changes

None.

Release notes snippet

Numerous formerly deprecated Drupal methods are not deprecated anymore due to changes in Symfony 5 that made incompatibility unfeasible otherwise:

  • Drupal\Core\TypedData\Validation\ConstraintViolationBuilder and its methods were deprecated in 9.3.0 but is no longer deprecated
  • Drupal\Core\TypedData\Validation\ExecutionContext and its methods were deprecated in 9.3.0 but is no longer deprecated
  • Drupal\Core\TypedData\Validation\ExecutionContextFactory and its methods were deprecated in 9.3.0 but is no longer deprecated
  • Drupal\Core\Validation\DrupalTranslator::transChoice() was depreacetd in 9.4.x-dev but is no longer deprecated
  • Drupal\Core\Validation\TranslatorInterface was deprecated in 9.3.0 but is no longer deprecated
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

longwave created an issue. See original summary.

longwave’s picture

Ugh, so what do we do here? The upstream TranslatorInterface is

    public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string;

However we return a TranslatableMarkup or PluralTranslatableMarkup object. We could just cast these to string, but we also protect against translating a previously-translated string - this will be bypassed if we cast the return value.

    // If a TranslatableMarkup object is passed in as $id, return it since the
    // message has already been translated.
    if ($id instanceof TranslatableMarkup) {
      return $id;
    }
longwave’s picture

longwave’s picture

Status: Active » Needs review
FileSize
1.83 KB

Let's try naively casting to string, as I'm not sure what else we can do to satisfy the upstream interface.

I guess if $id and the return value are both strings, Symfony must ensure this is not called twice already - maybe the safeguard is not needed?

Status: Needs review » Needs work

The last submitted patch, 4: 3255245-4.patch, failed testing. View results

Taran2L’s picture

This piece of core looks pretty weird tbh, see https://git.drupalcode.org/project/drupal/-/blob/10.0.x/core/lib/Drupal/...

DrupalTranslator implements TranslatorInterface, but TranslatorInterface has only methods (trans and getLocale), but comments state opposite, for example:

/**
   * {@inheritdoc}
   */
  public function transChoice($id, $number, array $parameters = [], $domain = NULL, $locale = NULL) {

/**
   * {@inheritdoc}
   */
  public function setLocale($locale) {
    $this->locale = $locale;
  }

Seems like this is old code, that is not used anywhere.

Then, more to add, DrupalTranslator itself is not widely used. Actually, I have found only core usage and single contrib module, according to this: http://grep.xnddx.ru/search?text=DrupalTranslator&filename=

Thus, it might be changed more dramatically between 9 and 10.

longwave’s picture

::transChoice() was deprecated in Symfony 4, I raised #3255250: [Symfony 5] TranslatorInterface::transChoice() is deprecated to deal with that separately.

This code is glue between Drupal's translation system and Symfony's; Symfony's validation engine (used by typed data) requires a class compatible with Symfony TranslationInterface, but otherwise Drupal uses its own translation system.

Taran2L’s picture

this is a very interesting topic, as currently Symfony\Contracts\Translation\TranslatorInterface comes not from regular Symfony packages, but on contracts ones, in particular in D9 it comes from symfony/translation-contracts and has version v2.5.0 (with my live 9.3.0 project) and it already do not have ::transChoice(), so it's like that for a long time and it probably can be just safely removed.

See https://github.com/symfony/translation-contracts

Taran2L’s picture

Probably, in D10 those contracts packages should be updated to version ^3

$ composer info "symfony/*" | grep contracts                                                                                     
symfony/cache-contracts            v2.5.0  Generic abstractions related to caching
symfony/deprecation-contracts      v2.5.0  A generic function and convention to trigger deprecation notices
symfony/event-dispatcher-contracts v1.1.11 Generic abstractions related to dispatching event
symfony/http-client-contracts      v2.5.0  Generic abstractions related to HTTP clients
symfony/service-contracts          v2.5.0  Generic abstractions related to writing services
symfony/translation-contracts      v2.5.0  Generic abstractions related to translation
longwave’s picture

The fails here are all where HTML appears in the error message, it is now being escaped when it shouldn't be. For example in CommentAnonymousTest:

1) Drupal\Tests\comment\Functional\CommentAnonymousTest::testAnonymous
Behat\Mink\Exception\ResponseTextException: The text "The name you used (msJs9ciF) belongs to a registered user." was not found anywhere in the text of the current page.

Because the placeholder HTML is escaped:

The name you used (<em class="placeholder">msJs9ciF</em>) belongs to a registered user.

Not sure yet where this is happening, nor how to solve this.

longwave’s picture

longwave’s picture

I think the quick fix is to revert #3231683: [Symfony 6] A number of methods of the class Drupal\Core\TypedData\Validation\ExecutionContext are considered internal and Drupal should not override them. and then we don't need to implement Symfony's TranslatorInterface, instead we use our own.

longwave’s picture

Fix deprecation skip.

andypost’s picture

Drupal\Tests\comment\Functional\CommentAnonymousTest::testAnonymous()

Maybe it's just unlocked some issue in comment module?

longwave’s picture

> Maybe it's just unlocked some issue in comment module?

That was just an example, all 40 fails in #4 are HTML that is now incorrectly escaped.

longwave’s picture

If this revert goes in it looks like we can remove our dependency on symfony/translation, we don't use it anywhere else, not sure why we depended on it in the first place.

murilohp’s picture

Hey @longwave, this is just a suggestion, but if we follow the approach of removing symfony/translation, what do you think about typehint our own interface to return a MarkupInterface instead of string(patch #4, method trans).

murilohp’s picture

The following review is from the patch #4, and I'm assuming we're going to keep the idea of type hinting the class.

+++ b/core/lib/Drupal/Core/Validation/DrupalTranslator.php
@@ -74,7 +74,7 @@ public function setLocale($locale) {
     return $this->locale ? $this->locale : \Drupal::languageManager()->getCurrentLanguage()->getId();

What do you think about removing the unnecessary $this->locale here? I mean use something like:
return $this->locale ?? \Drupal::languageManager()->getCurrentLanguage()->getId();

daffie’s picture

Priority: Normal » Critical

Reverting #3231683: [Symfony 6] A number of methods of the class Drupal\Core\TypedData\Validation\ExecutionContext are considered internal and Drupal should not override them. and doing mostly the same thing as Symfony, only a little bit different does not make me very happy. To me, we should see if we can do the same thing as Symfony. Drupal is a Symfony app.

Bumping this to critical as this issue is blocking Symfony 6 in D10.

daffie’s picture

Assigned: Unassigned » daffie

Working on this.

daffie’s picture

Assigned: daffie » Unassigned
FileSize
51.7 KB
49.78 KB

The patch is the same as the patch from comment #4, only with failures fixed.

Edit: The change from variables with %value to @value is necessary because variables that start with an "%" will get '' added before the value and '' added at the end. Variables that start with "@" do not get that. The required return type hint by Symfony make it so that less is possible. The problem is only for validation contstraint violations messages. To me, this is something we shall have to learn to accept. Not that I am happy about it.

murilohp’s picture

Hey @daffie I liked your solution, it's the original approach and I think we should follow the idea of doing the same thing as Symfony.

About the code:

+++ b/core/lib/Drupal/Core/Validation/DrupalTranslator.php
@@ -74,8 +74,8 @@ public function setLocale($locale) {
+    return $this->locale ?? \Drupal::languageManager()->getCurrentLanguage()->getId();

Thanks! For the change!

+1 for me to RTBC this!

Gábor Hojtsy’s picture

Hm, is that the only way to go for validation constraints? That sounds like a stepping stone that could lead to more things that we need to change in the future.

alexpott’s picture

Issue summary: View changes

I've opened https://github.com/symfony/symfony/pull/44911 so we can see what Symfony thinks about extending the scope.

catch’s picture

Given the direction that https://github.com/symfony/symfony/pull/44911 is taking (going nowhere), I think we should do #3255245-14: [Symfony 6] Revert 3231603 to use our own TranslatorInterface here.

Then we should open a follow-up to track whether there's an alternative approach, and also revisit #3054535: Discuss whether to decouple from Symfony Validator again.

Gábor Hojtsy’s picture

That makes sense. Let's send in #14 again for another round then :)

Status: Needs review » Needs work

The last submitted patch, 27: 3255245-14.patch, failed testing. View results

Spokje’s picture

Status: Needs work » Needs review
FileSize
37.9 KB
1.77 KB

Looks like #3255250: [Symfony 5] TranslatorInterface::transChoice() is deprecated doesn't like the way this issue is evolving...

Spokje’s picture

FileSize
3.13 KB
39.27 KB

Ouch, but looking at #3255250-3: [Symfony 5] TranslatorInterface::transChoice() is deprecated this approach might be better anyway.

Status: Needs review » Needs work

The last submitted patch, 30: 3255245-30.patch, failed testing. View results

Gábor Hojtsy’s picture

Issue tags: +Symfony 6

The fails are all seem to be due to the transChoice() method missing, that the patch removes :) I don't think we should remove it, just not deprecate it like the rest of the things we are not deprecating?

Spokje’s picture

FileSize
39.05 KB
2.91 KB

Thanks @Gábor Hojtsy, you're right, looks like undeprecating (my English spellchecker is hating me even more today...) is the way to go.

Let's see if I got it right this time

Spokje’s picture

Status: Needs work » Needs review
longwave’s picture

Status: Needs review » Needs work
Issue tags: +Needs issue summary update

The revert patch looks good, but the issue title is now incorrect and the summary needs an update.

hmendes’s picture

Title: [Symfony 6] Add typehints to Drupal\Core\Validation\DrupalTranslator » [Symfony 6] Revert 3231603 to use our own TranslatorInterface
Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs issue summary update

Updating the title and the proposed resolution from the IS with the comment #12

Gábor Hojtsy’s picture

Issue summary: View changes

Added a release notes snippet as well and further expanded the issue summary.

daffie’s picture

Status: Needs review » Reviewed & tested by the community

All code changes look good to me.
The patch is reverting the patch from #3231603: Allow reducing scope for selected modules.
The problem from that issue now need to be fixed in another way. I have created #3258380: [Symfony 6][Second try] A number of methods of the class Drupal\Core\TypedData\Validation\ExecutionContext are considered internal and Drupal should not override them. for that problem.
I have linked this issue to the CR from the issue we are reverting. That CR needs to be unpublished.
For me it is RTBC.

alexpott’s picture

Version: 10.0.x-dev » 9.3.x-dev
Status: Reviewed & tested by the community » Fixed

Committed d28e89b and pushed to 10.0.x. Thanks!
Committed 1201aa8 and pushed to 9.4.x. Thanks!
Committed 4bb9f46 and pushed to 9.3.x. Thanks!

I fixed the conflict in 9.3.x core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php - hopefully tests won't fail but if they do - I'll hotfix.

  • alexpott committed d28e89b on 10.0.x
    Issue #3255245 by Spokje, longwave, daffie, Gábor Hojtsy, Taran2L,...

  • alexpott committed 1201aa8 on 9.4.x
    Issue #3255245 by Spokje, longwave, daffie, Gábor Hojtsy, Taran2L,...

  • alexpott committed 4bb9f46 on 9.3.x
    Issue #3255245 by Spokje, longwave, daffie, Gábor Hojtsy, Taran2L,...
Gábor Hojtsy’s picture

Thanks for updating the change record, I further updated it to make the undeprecation more visual and updated the title: https://www.drupal.org/node/3238432 Should we have a dedicated change record for the undeprecation?

daffie’s picture

Should we have a dedicated change record for the undeprecation?

No, I do not think so. Or did we do an official release with Drupal with original patch in it?

Gábor Hojtsy’s picture

Yes our deprecation was released in 9.3.0.

catch’s picture

Status: Fixed » Closed (fixed)

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