Problem/Motivation
Certain configurations of the Typogrify filter lead to errors.
- Enable the Typogrify filter for a text format.
- Set either "Thin space in abbreviations" or "Digit grouping in numbers" to something other than the default "Do nothing".
- Save the text format.
- Clear caches.
- Load any page that uses the text format.
You will get a WSOD and the Drupal log will report something like
Error: Access to undeclared static property: Drupal\typogrify\SmartyPants::$method in Drupal\typogrify\SmartyPants::smartNumbers() (line 684 of /app/modules/contrib/typogrify/src/SmartyPants.php)
Proposed resolution
Replace self::$method with a valid callback inside preg_replace_callback().
Fix related errors.
For now, the work-around is to leave those two settings at their default values.
Remaining tasks
Fix the error in the regular expression.
User interface changes
None
API changes
None
Data model changes
None
Release notes snippet
None
Original report by @migmedia
I stumbled upon 2 errors in SmartyPants.
PHP message: Error: Access to undeclared static property: Drupal\typogrify\SmartyPants::$replace_method in /var/www/drupal8/modules/contrib/typogrify/src/SmartyPants.php on line 834 #0 /var/www/drupal8/modules/contrib/typogrify/src/Plugin/Filter/TypogrifyFilter.php(381): Drupal\typogrify\SmartyPants::smartAbbreviation('<p>Bei Fragen o...', '3')
#1 /var/www/drupal8/core/modules/filter/src/Element/ProcessedText.php(118): Drupal\typogrify\Plugin\Filter\TypogrifyFilter->process('<p>Bei Fragen o...', 'de')
#2 [internal function]: Drupal\filter\Element\ProcessedText::preRenderText(Array)
#3 /var/www/drupal8/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php(100): call_user_func_array(Array, Array)
#4 /var/www/drupal8/core/lib/Drupal/Core/Render/Renderer.php(781): Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_ren...', 'silenced_deprec...', 'Drupal\\Core\\Ren...')
#5 /var/www/drupal8/core/lib/Drupal/Core/Render/Renderer.php(372): Drupal\Core\Render\Renderer->doCallback('#pre_rend" while reading response header from up
stream, client: 192.168.80.62, server: ...
PHP message: Error: Access to undeclared static property: Drupal\typogrify\SmartyPants::$method in /var/www/drupal8/modules/contrib/typogrify/src/SmartyPants.php on line 684 #0 /var/www/drupal8/modules/contrib/typogrify/src/Plugin/Filter/TypogrifyFilter.php(386): Drupal\typogrify\SmartyPants::smartNumbers('<p>Bei Fragen o...', '3')
#1 /var/www/drupal8/core/modules/filter/src/Element/ProcessedText.php(118): Drupal\typogrify\Plugin\Filter\TypogrifyFilter->process('<p>Bei Fragen o...', 'de')
#2 [internal function]: Drupal\filter\Element\ProcessedText::preRenderText(Array)
#3 /var/www/drupal8/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php(100): call_user_func_array(Array, Array)
#4 /var/www/drupal8/core/lib/Drupal/Core/Render/Renderer.php(781): Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_ren...', 'silenced_deprec...', 'Drupal\\Core\\Ren...')
#5 /var/www/drupal8/core/lib/Drupal/Core/Render/Renderer.php(372): Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, A" while reading response header from upstream, client: 192.168.80.62, server: ...
It's an invalid use of self::$variable to reference a local variable, not a class-member.
This is fixed by:
diff --git a/src/SmartyPants.php b/src/SmartyPants.php
index 2660351..a8b82c5 100644
--- a/src/SmartyPants.php
+++ b/src/SmartyPants.php
@@ -681,7 +681,7 @@ class SmartyPants {
$number_finder = '@(?:(&#\d{2,4};|&(#x[0-9a-fA-F]{2,4}|frac\d\d);)|' .
'(\d{4}-\d\d-\d\d)|(\d\d\.\d\d\.\d{4})|' .
'(0[ \d-/]+)|([+-]?\d+)([.,]\d+|))@';
- $t = preg_replace_callback($number_finder, self::$method, $t);
+ $t = preg_replace_callback($number_finder, $method, $t);
}
$result .= $t;
}
@@ -831,7 +831,7 @@ class SmartyPants {
$t = $cur_token[1];
if (!$in_pre) {
$abbr_finder = '/(?<=\s|)(\p{L}+\.)(\p{L}+\.)+(?=\s|)/u';
- $t = preg_replace_callback($abbr_finder, self::$replace_method, $t);
+ $t = preg_replace_callback($abbr_finder, $replace_method, $t);
}
$result .= $t;
}
Thanks for porting this module to d8.
migmedia
| Comment | File | Size | Author |
|---|---|---|---|
| #17 | 3133951-17.patch | 5.03 KB | benjifisher |
| #17 | 3133951-17-test-only.patch | 4.02 KB | benjifisher |
| #17 | interdiff-3133951-15-17.txt | 1.18 KB | benjifisher |
| #15 | 3133951-15.patch | 4.88 KB | benjifisher |
| #15 | 3133951-15-test-only.patch | 3.87 KB | benjifisher |
Issue fork typogrify-3133951
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:
Comments
Comment #2
migmedia commentedComment #3
benjifisherComment #4
benjifisherI am afraid it is more complicated than that.
I am updating the issue summary, including steps to reproduce the problem. When I follow those steps with an unpatched version of the module, I get a WSOD and the error you describe:
When I apply the patch from Comment #2, I no longer get the WSOD, but the filter is not wrapping the numbers and I see this in the log:
So we need some variant of
self::$methodto identify the method. One option is to use[__CLASS__, $method]. When I do that, this is what I see in the log:That means there is something wrong with this regular expression:
I think the invalid range refers to this part:
[ \d-/]. Do we know what that regular expression is supposed to do? Is it the same as what we have in the D7 version?It may be that we are running into differences between PHP 5 and PHP 7, both in the use of
selfand in regular expressions. Or maybe we just garbled things when updating the code for Drupal 8.I will start by adding some failing tests and correctly calling the methods. Maybe someone else can help with the regular expression.
I am leaving the status at NW in order to trigger the testbot, but I expect both the test-only patch and the "real" one to fail. The "real" one should generate the last warning quoted above.
Comment #6
benjifisherA quick search on the PHP warning led me to preg_match(): Compilation failed: invalid range in character class at offset on StackOverflow. Based on the answer there, the invalid range warning may be due to a change in PHP 7.3. If so, then the patch in #4 may pass. I queued a second test using PHP 7.3, which is the version I am using locally.
If the patch in #4 does pass with PHP 7.1, then I may decide to commit it, since the problem with the regular expression is a separate issue.
Comment #7
benjifisherThat was quick! The testbot must be stuck at home and bored, just like everyone else.
Let me see if I can fix the regular expression. The automated test was not quite right, so I am attaching an updated test-only patch as well as one that I hope to pass and an interdiff.
Comment #9
benjifisherYay, the testbot approves!
I would like to get some real-world testing, and maybe even a code review, before committing this patch, so I will leave the status at NR. In particular, that change to the regular expression could use a second look.
Comment #10
benjifisherI forgot to un-assign myself.
Comment #11
wim leers+1 for this syntax.
Nit: you could typehint
$originaland$processedtoo.👍 for
$extra_settingsas the first operand for the+operator; that means that settings in there always win of those in$this→baseSettings(the second operand).🤔 Why
assertEqual()and notassertSame()?Übernit: s/compatibility-test/compatibility test/
FYI
@dataProvidertest case labels are free form — they can contain spaces and even emoji.Comment #12
benjifisherThanks for the review!
Thanks.
TIL that type hints are now called Type declarations in PHP 7. Checking that page, I see that
stringis an allowable declaration since PHP 7.0.0. I am a little worried that people might still be running an old version of Drupal 8 that allows PHP 5.6, but since this is in the test I think I will take the suggestion. Fixed.Yes, I see this pattern a lot in Drupal.
No good reason: it was like that when I got here. I wish the API docs for KernelTestBase had links to the methods in
PHPUnit\Framework\Assert, such asassertSame()ansassertEquals(). As in (2) I will not worry too much about BC for the tests. Fixed.Fixed.
Thanks for the tip. I am not a fan of emojis, but some spaces will be an improvement. While I am at it, I will use the actual option name:
wrap_abbrinstead ofwrap_abbreviations.Comment #15
benjifisherIt turns out there was a reason to use
assertEqual()instead ofassertSame().Since
assertEqual()is deprecated (useassertEquals()instead) I will not go back. Instead, cast FilterProcessResult to string.Comment #17
benjifisherThe attached patch makes two changes to the test:
assertEquals()instead of casting to string and then usingassertSame().wrap_numbersoption more thoroughly.You can see the two changes separately in the issue fork.
The first change reverses the decision I made in #15.
Since the problem is caused by an un-escaped
-character in a regular expression, I decided that thewrap_numberstest should include that character.Comment #20
benjifisherI did my best to review my own patch with "fresh eyes" before making the additional changes in #17. Fixed.