We're seeing this PHP Notice "Notice: Trying to get property 'language' of non-object in scheduler_tokens()" on our sites. When you look at
line 34 of modules/contrib/scheduler/scheduler.tokens.inc which is this line of code $language_code = isset($options['language']) ? $options['language']->language : NULL; and $options['language']->language is treating an array a an object which is causing the error.

It seems the fix is simply to change $options['language']->language to $options['language'].

Notice: Trying to get property 'language' of non-object in scheduler_tokens() (line 34 of modules/contrib/scheduler/scheduler.tokens.inc).

scheduler_tokens('site', Array, Array, Array, Object)
call_user_func_array('scheduler_tokens', Array) (Line: 403)
Drupal\Core\Extension\ModuleHandler->invokeAll('tokens', Array) (Line: 304)
CommentFileSizeAuthor
#2 scheduler-notice-error-3144568-2.patch647 byteskamkejj

Comments

kamkejj created an issue. See original summary.

kamkejj’s picture

StatusFileSize
new647 bytes

Patch for this change.

kamkejj’s picture

kamkejj’s picture

Status: Active » Needs review
jasonawant’s picture

Status: Needs review » Needs work

@kamkejj,

I wonder why scheduler_tokens() assumes $options['language'] is an object. Did you see any instances where it was an object and can you share the stack traces or origins?

I wonder if this change breaks other usages.

/**
 * Implements hook_tokens().
 */
function scheduler_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
  $token_service = \Drupal::token();
  $date_formatter = \Drupal::service('date.formatter');
  $language_code = isset($options['language']) ? $options['language']->language : NULL;
....

From hook_tokens documentation ,

array $options: An associative array of options for token replacement; see \Drupal\Core\Utility\Token::replace() for possible values.

And \Drupal\Core\Utility\Token::replace(),

array $options: (optional) A keyed array of settings and flags to control the token replacement process. Supported options are:

  • langcode: A language code to be used when generating locale-sensitive tokens.
  • callback: A callback function that will be used to post-process the array of token replacements after they are generated.
  • clear: A boolean flag indicating that tokens should be removed from the final text if no replacement value can be generated.

$options['langcode'] is intended to be just that, a langcode...not an language object.

I imagine something is calling Token::replace() with a language object instead of the langcode. In which case, what breaks with this change? And, do we need to report an issue some where else to correct this usage.

kamkejj’s picture

Hey @jasonwant

The short answer.

When I step debugged I only saw "$options['language']" as an array and not an object which is why I proposed this change. As it iterrerated over "function scheduler_tokens" sometimes "$options" was empty and sometimes it was an array with language as a key and without the language key.

jonathan1055’s picture

Hi kamkejj and jasonawant,
Thanks for finding and reporting this problem. I looked back using git blame and that line has not been changed since January 2011!

1dbc0554 (joekers         2016-03-06 12:49:00 +0000 31) function scheduler_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
1dbc0554 (joekers         2016-03-06 12:49:00 +0000 32)   $token_service = \Drupal::token();
523f1346 (Kab00m          2015-12-31 19:54:10 +0100 33)   $date_formatter = \Drupal::service('date.formatter');
e6c1de0b (Eric Schaefer   2011-01-31 19:13:43 +0000 34)   $language_code = isset($options['language']) ? $options['language']->language : NULL;
b96e0215 (jonathan1055    2017-03-21 15:45:24 +0000 35)   $replacements = [];
e6c1de0b (Eric Schaefer   2011-01-31 19:13:43 +0000 36) 

At that time Scheduler 6.x-1.8 was the current release and Scheduler 7.x-1.0 was being finalised. The issue which added scheduler.tokens.inc was #960030: Scheduler token support

I wonder why scheduler_tokens() assumes $options['language'] is an object.

I don't know. But according to your helpful research is should always be a string. However, you say that it is $options['langcode'] which has the language code, so we should use that, and not $options['language']?

drupal.ninja03’s picture

I am on Drupal 8.8.6, PHP 7.2. I am not able to reproduce the error. Can you provide the steps?

jonathan1055’s picture

Yes, thanks @drupal.ninja03 that is exactly what I was going to ask for. I need to be able to reproduce the problem to prove that the patch fixes it. I am also confused as to the documentaion on \Drupal\Core\Utility\Token::replace() which states that the key is 'langcode' and no mention of key 'language'. So why would the $options['language']->language even be attempted to get evaluated?

jonathan1055’s picture

By the way, I will be release Scheduler 8.x-1.3 in a few days, due to needing to fix #3145169: User messages are not displayed after updating to 8.x-1.2 so if we can get a solution here it can be included in the next release.

kamkejj’s picture

Hi @drupal.ninja03 and @jonathan1055

Did some more research and step debugging of our custom code. I think there's still an issue with $language_code = isset($options['language']) ? $options['language']->language : NULL; in scheduler.tokens.inc, just a slightly different one that's actually the Drupal 7 version. As @drupal.ninja03 pointed out this is code from 2011.

I just found custom code that's setting the language key in the array

$tokenized_value = \Drupal::service('token')
            ->replace($value, [], [
              'callback' => '***_component_layer_intl_numbers',
              'language' => $field->getLangcode(),
            ]);

where the "language" key is the Drupal 7 version of the possible values for $options in hook_tokens(). See https://api.drupal.org/api/drupal/includes%21token.inc/function/token_re...

For Drupal 8 this was changed to "langcode" as we see in an example of the $options array value when debugging the code.

result = {array} [2]
 langcode = "en"
 clear = true

I think $language_code = isset($options['language']) ? $options['langcode']->language : NULL; should be changed to $language_code = isset($options['langcode']) ? $options['langcode']: NULL; in order to get the language code?

As Jason pointed out above in comment #5 that valid values for $options, Drupal 8, are langcode, clear, callback as we can see in the docs at https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Utility%2...

If you agree I can either open a new issue with a new patch or post a new patch in this issue. Thoughts?

Thanks

BTW, We are on Drupal 8.8.5.

kamkejj’s picture

StatusFileSize
new647 bytes

Made a patch anyway that updates
$language_code = isset($options['language']) ? $options['language']->language : NULL;
which seems to be the Drupal 7 version to the Drupal 8 version of the possible values for $options.

Drupal 7 docs https://api.drupal.org/api/drupal/includes%21token.inc/function/token_re...

Drupal 8 docs https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Utility%2...

Refer to comment #11 for details. Also hid the previous patch.

jonathan1055’s picture

Status: Needs work » Needs review

I just found custom code that's setting the language key in the array

A-ha, that explains my question in #9 "So why would the $options['language']->language even be attempted to get evaluated?" it was your custom code setting the 'language' key when it should now be setting the 'langcode' key.

Your patch #12 is exactly what I was expecting the change to be. But can you give me the steps to reproduce the original error. I have enabled language and language translation, enabled token and token_filter, created content with translations, but still in scheduler_tokens() for $options I only get an empty array, or with key 'clear' but no other keys.

jasonawant’s picture

Status: Needs review » Needs work

Hi jonathan1055,

I found custom project code that set the $options['language']. Once that was removed; I did not find another usage.

Regarding the following, I couldn't tell you why. I suspect this was missed during Drupal 8 port as the Drupal 7 usage did specify the language key and language object. See Drupal 7 token_replace docs.

not been changed since January 2011

I can not find usage of the following as examples of array key assignment within scheduler itself.

  • 'language' =>
  • $options['language'] =

I think the right path forward is to replace the current logic with

$language_code = isset($options['langcode']) ? $options['langcode'] : NULL;
jonathan1055’s picture

Thanks @jasonawant. Yes we all agree on the chnage required. That is what patch #12 had, so was there a reason why you hid that patch and set the status to 'needs work'? If that was an error, just set it to RTBC and I will commit this.

jasonawant’s picture

Status: Needs work » Reviewed & tested by the community

Whoops, sorry! My apologies to everyone; I was looking at a stale page!

  • jonathan1055 committed 474eb8b on 8.x-1.x authored by kamkejj
    Issue #3144568 by kamkejj, jasonawant: Notice: Trying to get property '...
jonathan1055’s picture

Status: Reviewed & tested by the community » Fixed

Thanks @kamkejj and @jasonawant. This will be in Scheduler 8.x-1.3 which I'm going to release tomorrow.

kamkejj’s picture

Thanks @jonathan1055

Just to follow up on steps to reproduce. With at least one other language enabled and a content type set to be translatable. Create a new node or edit an existing translatable node and look at the value of $options['language'].

In our project I always see the langocde key set to "en".

jonathan1055’s picture

@kamkejj, yes I have done all that, as explained in #13. Your site must have other modules which are using/providing tokens. It is those other modules that we need to look at. Or if it is only your custom module, and not a contrib module that I can download, then I can't really test this. But we agree now what the right change is, and I have committed it.

Status: Fixed » Closed (fixed)

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