-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding a basic cache-flushing mechanism #11
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dig the general approach of caching the rather-static site details, but it looks like this PR is implementing some very specific logic to a framework that's meant to be rather agnostic by default.
What are your thoughts on additional filtering within the Thing::build()
method to enable additional, potentially-cached content before any other queries are run? This could give site-specific code the ability to change the values returned from the cache, potentially solving the same problem in a more isolated way.
As always, thank you for your pull request and please accept my apologies that I missed the notification email!
tests/PHPUnit/schemas/ThingTest.php
Outdated
@@ -7,6 +7,13 @@ | |||
|
|||
namespace Schemify\Schemas; | |||
|
|||
define( 'MINUTE_IN_SECONDS', 60 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than redefining these values in ThingTest.php
, they should be added to the test bootstrap file for easy re-use.
includes/cache.php
Outdated
* @param int $post_id The post being updated. | ||
*/ | ||
function update_post_cache( $post_id ) { | ||
wp_cache_delete( sprintf( 'schema_%s', $post_id ), 'schemify' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason this isn't leveraging the get_key()
function defined just above it?
includes/cache.php
Outdated
* @return string A cache key to be used with the WP object cache. | ||
*/ | ||
function get_key( $object_id, $object ) { | ||
return sprintf( 'schema_%s', $object_id ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If $object
isn't being used, we don't really need it as an argument.
includes/cache.php
Outdated
'posts_per_page' => 5000 | ||
) ); | ||
|
||
foreach ( $author_posts as $post_id ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests/PHPUnit/schemas/ThingTest.php
Outdated
) ); | ||
|
||
M::userFunction( 'wp_cache_get', array( | ||
'times' => 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've recently learned this lesson the hard way, but you want to use the 'times' argument sparingly when testing — if you're expecting a result to match the return value of a function call, it can be assumed that the function was called. Counting the number of times it was called is usually not particularly helpful, unless it's more of a "I need to make sure this function was called X number of times, because it has other side effects."
For example, consider the following functions:
/**
* Create a heading.
*
* @param string $text The text for the new heading.
* @return string A new <h1> element.
*/
function make_heading() {
track_headings( $text );
return '<h1>' . shout( $text ) . '</h1>';
}
/**
* Convert a string to uppercase and append exclamation marks.
*
* @param string $string The string to modify.
* @return string The string but, you know, louder.
*/
function shout( $string ) {
return strtoupper( $string ) . '!!!';
}
/**
* Keep track of headings being used on the page.
*
* By the time I wrote this, the example was going off the rails a bit. Sorry 'bout that.
*
* @global $all_headings
*
* @param string $heading The heading text.
*/
function track_headings( $heading ) {
global $all_headings;
$all_headings[] = $heading;
}
When testing make_heading()
, we don't necessarily care that shout()
was called, as long as the result is what we expect:
public function test_make_heading() {
$this->assertEquals(
'<h1>THIS IS A HEADING!!!</h1>',
make_heading( 'this is a heading' )
);
}
Since track_headings()
doesn't have an effect on the output, however, we may want to ensure that gets called:
public function test_make_heading_calls_track_headings() {
M::passthruFunction( __NAMESPACE__ . '\track_headings', array(
'times' => 1,
'args' => array( 'this is a heading' ),
) );
make_heading( 'this is a heading' );
}
I'll be the first to admit that I've been overzealous about using WP_Mock for :allthethings: in the past, and the result has been tightly-coupled tests that break if any detail of the implementation changes. Hopefully I can serve as a cautionary tale! 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I'm not a huge fan of WP_Mock, it's boring to mock all those basic functions and I always have the feeling that the tests are biased and it's not really testing anything, The only reason I added times
was because I was seeing it being used across tests. I'm totally fine removing it. if you think it makes sense :)
For these tests, if the function call doesn't happen the test will fail anyway, so times
is not that important here.
@@ -191,7 +195,11 @@ protected function build( $post_id, $is_main ) { | |||
|
|||
// Cache the result (top-level only) so we don't have to calculate it every time. | |||
if ( $is_main ) { | |||
wp_cache_set( $cache_key, $data, 'schemify', 0 ); | |||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { | |||
$data['cached'] = date( 'Y-m-d H:i:s' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the date of the cache time is stored in the {$cache_key}_last_update
cache, why duplicate it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cache expires after 12h. So the post might not chang but cache can still expire. For debug purposes that date was meant to be when the cache was recreated and not when the post was last updated
@stevegrunwell I pushed some changes to address your feedback! Thanks for you time looking into this. By adding filtering on Thing::build() you mean moving the cache purging logic to cache.php by hooking into those filters/actions? If so that makes sense to me, I only kept the logic there because there was already some caching logic there. Let me know what you think. |
Merging the latest changes here, I'll take another pass and recreate the tests. @stevegrunwell are you still open to merge this PR? |
@nicholasio Definitely still open, my time on Schemify has been really scattered. Hoping to be able to get back to this towards the end of this week :) |
Introduces a basic cache flushing mechanism. #4.