abstract class DrupalCacheArray has 2 private properties, $cid and $bin. class ThemeRegistry extends it, and override the set() method. function __destruct() calls set() and passes the private properties as arguments. It's a bit weird to me but the overridden set() couldn't see the arguments.

I doubt you want to pass own properties as arguments to a own protected method. But at least the properties shouldn't be private. I'll upload a patch.

Anyone see the same issue?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

makara’s picture

A simple patch.

makara’s picture

Status: Active » Needs review
catch’s picture

Version: 7.x-dev » 8.x-dev
Component: cache system » base system
Issue tags: +Needs backport to D7

Hmm, set() takes those as arguments in case an implementation wants to set the cache with something other than what's in the property, but we could probably force people to override it.

The change from protected to private looks dead right though, this will need commit to 8.x first than backport to 7.x.

I think neclimdul spotted something like this in terms of theme registry caching, I've pinged him to ask him to take a look - it's possible we could turn that into a test case.

Damien Tournoud’s picture

Private has no place in Drupal. Those should have been protected from the get go.

makara’s picture

The patch for D8. No test case yet.

chx’s picture

Status: Needs review » Reviewed & tested by the community
Dries’s picture

Version: 8.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Committed to 8.x. Moving to 7.x.

sun’s picture

@Dries: Your commit additionally removed phpDoc, which wasn't contained in this patch and should not have been removed:
http://drupalcode.org/project/drupal.git/commitdiff/7be846e75d21c83a92ee...

xjm’s picture

Oh so that's how that got fixed in D8. Edit: See #1366804-4: "End of foo group" on a couple of API pages due to not following standards. It's a needed change, just part of a different issue. :)

makara’s picture

Status: Patch (to be ported) » Needs review

#1: 1371484-private_properties-1.patch queued for re-testing.

catch’s picture

Status: Needs review » Reviewed & tested by the community

I was going to ask for tests for this, but it's also an obvious issue since we don't allow private properties anyway (not sure how I ended up getting those in the original patch and past reviewers..), and since it's already committed to 8.x it's RTBC for 7.x as well then.

makara’s picture

A follow-up question.

Hmm, set() takes those as arguments in case an implementation wants to set the cache with something other than what's in the property, but we could probably force people to override it.

I think the set() function in class ThemeRegistry is already confused by the arguments. It's using bin from both the arguments and its properties.

Am I wrong or shall we do something to this?

catch’s picture

No that looks like an oversight - worth opening a separate issue for.

webchick’s picture

Status: Reviewed & tested by the community » Fixed

While technically an API change for D7, this is only going to open opportunities people extending the class didn't have before so there shouldn't be any harm.

I'm not sure about that "never, ever use private" rule though, or when/who/why that was added to http://drupal.org/coding-standards (my kingdom for a 'blame' feature in Diff module :)). In terms of API design, the "private" keyword is actually very useful, if that's what you want. However, it seems here we don't, so...

Committed and pushed #1 to 7.x. Thanks!

catch’s picture

Version: 7.x-dev » 8.x-dev
Category: bug » task
Priority: Major » Normal
Status: Fixed » Active
Issue tags: +Needs tests

Let's add a test for this.

xjm’s picture

xjm’s picture

Status: Active » Needs work

Reverted from 7.x and 8.x:

git revert 24c357b5c521ade1d900 # 7.x
git revert 7be846e75d21c83a92ee5e # 8.x

...by webchick, not me. :)

xjm’s picture

Closed #1391364: Latest 7.x dev(1/1/2012) throws WSOD if any theme enabled while overlay module enabled. as a duplicate. We either need to postpone this on a fix that makes ThemeRegistry not try to alter the formerly-and-again private variables in DrupalCacheArray, or roll a fix for that in with this patch. We should also come up with a unit test for that, since #1391364: Latest 7.x dev(1/1/2012) throws WSOD if any theme enabled while overlay module enabled. cannot be tested functionally.

xjm’s picture

Priority: Normal » Major

I guess this needs to get bumped back to major as well.

catch’s picture

FileSize
1.8 KB

Started looking at this. It looks like when the properties are protected, enabling the stark theme leads to seven's entry for the ThemeRegistry cache having only entries for toolbar module in it - so the WSOD is because as far as it's concerned, no other theme functions exist. This is due to ->set() not taking into account the fact we need a processed theme registry with NULL array keys when the cache is empty, rather than just taking whatever's set in $data. This would only ever be triggered when another request clears the theme registry cache in between the request starting and finishing, and without writing back to it which is probably why it's only ever triggered by the overlay.

We could likely simulate that in a test by initializing the theme registry class, requesting a theme function to trigger a cache write, then deleting the cache entry, then destroying the class so it calls __destruct() and tries to write to cache. Didn't get to that yet though.

While debugging this I found two further issues:

- $this->completeRegistry() was not avaialble in __destruct(). After re-initializing that variable it all works again, but that's not a proper fix for this (see patch for the hack).

While in there I noticed that l() is still calling theme_load_registry() and getting the full thing, that looks to have been lost in the final one or two re-rolls of the original issue. Ironically it is probably this omission that prevented this bug being found sooner, since any broken ThemeRegistry object is overwritten as soon as l() is called with the full version.

So @todos (at least):

- write a test that intializes the ThemeRegistry object, requests a theme function that's not cached yet, manually removes the cache item, then destroys the object, then initializes again and makes sure that all potential theme functions are available instead of just the one that was a cache miss.

- figure out wtf is going on with $this->completeRegistry() in __destruct (and probably move that array_fill_keys() logic to a helper function as well).

catch’s picture

Category: task » bug
pounard’s picture

Got the bug while debugging lock system, having those properties as private do break the theme cache implementation.

Why does the set() method has cid and bin as parameters anyway?

catch’s picture

That was in there to support writing to more than one cache entry without having to reimplement the locking, however in practice no implementations are using this any longer so it should go.

catch’s picture

Status: Needs work » Needs review
FileSize
3.94 KB

Here's a test that will fail properly in the same way as the one enabling a theme from inside the overlay.

CNR for the bot.

catch’s picture

FileSize
7.86 KB

This one should pass, also refactored the array_keys() stuff into a helper method.

Status: Needs review » Needs work

The last submitted patch, pass_please.patch, failed testing.

catch’s picture

Status: Needs work » Needs review
FileSize
7.87 KB

Missed a bit.

makara’s picture

Great.

BTW, the fail_please.patch in #24 fails on my local.

xjm’s picture

+++ b/core/modules/simpletest/tests/theme.testundefined
@@ -540,3 +540,56 @@ class ThemeHtmlTplPhpAttributesTestCase extends DrupalWebTestCase {
+   * Test the behaviour of the theme registry class.

Nits:

  1. Should be "Tests."
  2. British spelling of "behavior." :) (Edit: In getInfo() as well.)

The test-only patch was postponed on QA, so I requeued it manually. It also fails for me locally. So as I understand the test basically emulates the sequence of events for the registry when the theme is enabled from within overlay?

Edit: Another nitpick is that the assertion message "Value NULL is TRUE" is not so useful so maybe we could add custom assertion messages? Edit 2: Though I think sun would disagree on that point, and one can always check the line number, but...

xjm’s picture

Issue tags: +Novice

Tagging novice for the task of cleaning up the three things mentioned in #29 if no one else gets to it first.

Anonymous’s picture

Found this issue through the "Novice" tag - this is my first time working with patches. Cleaned up "Tests" and "behavior"s from #29. Not sure what to make of the "Value NULL is TRUE" item.

Anonymous’s picture

Status: Needs review » Reviewed & tested by the community

i reviewed the way we clear this data as part of reviewing this patch, and created #1394480: Improve granularity of theme registry cache clearing. i don't think we should tackle that here, but really, even after this patch, things are ungood.

looking at the test, i can see that it should work with a $cid of 'test_theme_registry', but ugh, it really shows how the coupling is just weird. that is, the $cid we pass to ThemeRegistry can be completely arbitrary, because the data that is built is based on global 'what is the current theme' state - theme_get_registry() doesn't take any params to specify which theme. i don't we should fix that here, but ewwww.

soooo - i think this is good to go, then we can move on to #1394480: Improve granularity of theme registry cache clearing.

xjm’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: -Needs tests
+++ b/core/modules/simpletest/tests/theme.testundefined
@@ -540,3 +540,56 @@ class ThemeHtmlTplPhpAttributesTestCase extends DrupalWebTestCase {
+    $this->assertTrue(cache()->get($cid));
...
+    $this->assertTrue($registry['theme_test_template_test']);
...
+    $this->assertTrue(cache()->get($cid));
...
+    $this->assertTrue($registry['theme_test_template_test']);
+    $this->assertTrue($registry['theme_test_template_test_2']);

To clarify my previous comment, all these assertions are missing message text, and are just using the default "Value X is Y." See: DrupalTestCase::assertTrue().

Not going to set it back over that though. :P

xjm’s picture

Status: Needs review » Reviewed & tested by the community

Say one thing and do another. Awesome.

catch’s picture

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

Here it is with some messages.

xjm’s picture

Yay for more context for poor suckers scanning results on QA. :) That looks fine to me.

I reviewed the patch again and I think everything is clear, except for this:

+++ b/core/includes/common.incundefined
@@ -2336,7 +2336,7 @@ function l($text, $path, array $options = array()) {
-      $registry = theme_get_registry();
+      $registry = theme_get_registry(FALSE);

You mentioned this change was present originally in a previous issue, and was lost in its rerolls. So that fix is included here just to fix the unnecessary overhead, or is it related to the bug fix?

I also noticed that the backport will need to be more than just a simple reroll (since cache() does not exist in D7)?

xjm’s picture

Issue tags: -Novice

Oh, and the novice part is fixed. :) Thanks @ArtistConk!

catch’s picture

So that fix is included here just to fix the unnecessary overhead, or is it related to the bug fix?

That's just to fix the unnecessary overhead. It's related to the bug fix in the sense that it's been masking the fact this was broken in 99% of cases.

neclimdul’s picture

That theme_get_registry(FALSE); is a bit unclear. Should we add a comment explaining why its there so someone doesn't remove it again?

xjm’s picture

#39: I thought the same earlier, but before posting #36 I grepped core and there are one or two other other places it's used like that, with no comment. So, we could split that change off into a separate issue and add comments... or let it slide. :) Either way.

neclimdul’s picture

I was just making and observation and don't feel strongly either way. I'll leave it up to you since you've done a more in depth review of the patch. :)

xjm’s picture

Status: Needs review » Reviewed & tested by the community

I'm okay with it as well. RTBC I think. Depending how Dratchick feel, we can spin off a followup for to add the comments to theme_get_registry(FALSE) calls, or not.

I requeued the patch on QA so we should hopefully see green in a bit.

catch’s picture

Version: 8.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)
Issue tags: +Needs change record

I think it's worth a follow-up for the theme_get_registry() calls. The other one in core doesn't have this, so to save the patch getting bigger I'd rather not add here.

Also we should consider changing the argument default in Drupal 8 (or open an issue for a more thorough refactoring of the theme registry, this only fixes part of the performance issues with it, cache misses are still particularly bad).

I've committed/pushed this to 8.x (I wrote some of the patch but it is mostly test coverage), moving to 7.x for backport.

For D7 need to decide whether to break bc in the case that someone uses DrupalCacheArray and calls ->set() from their class, I'm 99% sure that no code exists that does this except for the code touched in this issue, but it may be possible to keep the same API but still fix the bug. I'd lead towards breaking the API - it's only been in core for 2-3 months and the use case here for calling set() directly is a fairly unusual one.

langworthy’s picture

Status: Patch (to be ported) » Needs work
FileSize
7.31 KB

Here's a first stab at a patch. I'm not too familiar with the differences between the 8.x and 7.x testing system (shame on me) so the tests need work.

I should point out that I was directed to this issue after running into problems trying to get MongoDB cache and watchdog to play nicely. In short the destructor in the ThemeRegistry class was being called but the constructor wasn't and I was getting an error. When using these MongoDB modules and ffter applying this patch I still get an error on install but now after clearing caches it is gone. Once I hit a new page the error returns.

langworthy’s picture

typo in the last patch. Everything is working great now :)

Still needs tests updated.

catch’s picture

The only obvious thing wrong in the test is:

+    cache_clear_all($cid);

this needs to be:

+    cache_clear_all($cid, 'cache')
langworthy’s picture

Status: Needs work » Needs review
FileSize
8.33 KB

I fixed cache_clear_all().

Basically copying from the D8 patch, I've added hook_theme() to theme_test.module and created the same placeholder theme_test.template_test.tpl.php file.

aspilicious’s picture

Status: Needs review » Needs work
+++ b/modules/simpletest/tests/theme_test.template_test.tpl.phpundefined
@@ -0,0 +1,2 @@
+Fail: Template not overridden.
\ No newline at end of file

Needs a newline in the end

Thats it I guess...

-23 days to next Drupal core point release.

langworthy’s picture

Status: Needs work » Needs review
FileSize
8.3 KB

added newline

catch’s picture

Status: Needs review » Reviewed & tested by the community

This looks exactly right as a straight backport of the Drupal 8 patch.

Note there's an API change here, it will affect modules that inherit from DrupalCacheArray and either override the set() method, or call it directly. Currently the only implementation I'm aware of in existence is the one in this patch. I also wrote every other implementation of DrupalCacheArray I'm aware of as well. This doesn't rule out someone using it somewhere in contrib or custom code somewhere, but it feels unlikely since it's pretty new, and designed for very specific use cases.

webchick’s picture

Title: Private properties in abstract class DrupalCacheArray » Change notice for: Private properties in abstract class DrupalCacheArray
Category: bug » task
Priority: Major » Critical
Status: Reviewed & tested by the community » Active

Ok, committed and pushed to 7.x. Let's try this again, gulp. :)

This needs a change notice. Catch said he is on it.

catch’s picture

Category: task » bug
Priority: Critical » Major
Status: Active » Fixed

Added here http://drupal.org/node/1422264. Thanks!

Tor Arne Thune’s picture

Title: Change notice for: Private properties in abstract class DrupalCacheArray » Private properties in abstract class DrupalCacheArray
xjm’s picture

Issue tags: -Needs change record

Untagging.

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