{"action":"created","issue":{"url":"https://api.github.com/repos/pixelandtonic/ElementAPI/issues/12","repository_url":"https://api.github.com/repos/pixelandtonic/ElementAPI","labels_url":"https://api.github.com/repos/pixelandtonic/ElementAPI/issues/12/labels{/name}","comments_url":"https://api.github.com/repos/pixelandtonic/ElementAPI/issues/12/comments","events_url":"https://api.github.com/repos/pixelandtonic/ElementAPI/issues/12/events","html_url":"https://github.com/pixelandtonic/ElementAPI/pull/12","id":147923895,"number":12,"title":"Enable caching of element queries","user":{"login":"AugustMiller","id":1895522,"avatar_url":"https://avatars.githubusercontent.com/u/1895522?v=3","gravatar_id":"","url":"https://api.github.com/users/AugustMiller","html_url":"https://github.com/AugustMiller","followers_url":"https://api.github.com/users/AugustMiller/followers","following_url":"https://api.github.com/users/AugustMiller/following{/other_user}","gists_url":"https://api.github.com/users/AugustMiller/gists{/gist_id}","starred_url":"https://api.github.com/users/AugustMiller/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AugustMiller/subscriptions","organizations_url":"https://api.github.com/users/AugustMiller/orgs","repos_url":"https://api.github.com/users/AugustMiller/repos","events_url":"https://api.github.com/users/AugustMiller/events{/privacy}","received_events_url":"https://api.github.com/users/AugustMiller/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":6,"created_at":"2016-04-13T01:53:27Z","updated_at":"2016-08-29T20:22:35Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/pixelandtonic/ElementAPI/pulls/12","html_url":"https://github.com/pixelandtonic/ElementAPI/pull/12","diff_url":"https://github.com/pixelandtonic/ElementAPI/pull/12.diff","patch_url":"https://github.com/pixelandtonic/ElementAPI/pull/12.patch"},"body":"I don't really know that this is worth a PR, but I wanted to get it in front of the team, in case there are some really obvious no-nos. I'd noticed a couple of other attempts at this, but for one reason or another, I decided to give it a go, myself…\r\n\r\nI'm working on a project that promises to have a certain volume of traffic that could begin to impact other site features without _some_ kind of caching for JSON responses. It seemed like the right time to experiment with modifying/contributing to a Craft project!\r\n\r\nWhat's been implemented:\r\n- Two new config settings, `cache` and `cacheDuration` to enable and configure query caching. They exist outside the `defaults` array, in part because (unrelated), config files that are not multi-environment aren't merged recursively. We also needed to fetch them throughout the plugin, not just as part of the `$config` array in the primary Controller action (which is really more of a set of default criteria)\r\n- A few new methods that proxy all element queries through some logic that determines whether to try the Craft cache before cold-fetching out of the database.\r\n- A method to build cache keys from attributes set on an `EntryCriteriaModel`\r\n\r\nA note on cache keys: I was experiencing an odd behavior with `ElementCriteriaModel` pre- and post-execution— the `locale` attribute was `null` _until any of the fetching methods were called_. That meant that building a lookup hash would be different than the one built from an query that had been executed. The locale had to be set prior to fetching to make sure that:\r\n- Cache keys matched for setting and getting data\r\n- Incoming and outgoing data was in the expected language (rather than always in the default language)\r\n\r\nThis key-building method was adopted from another plugin (which used just a single attribute), but I'm not convinced that this will comprehensively/uniquely describe all the parameters for an `EntryCriteriaModel`… Or that the language is correctly set by using `craft()->getLanguage()`. What is the typical approach in Craft for something like this? Is there any way to invalidate the cache when the underlying data changes?\r\n\r\nNow we've got ye' old bag of worms wide open. :smile: Any help is appreciated!\r\n\r\n:deciduous_tree:"},"comment":{"url":"https://api.github.com/repos/pixelandtonic/ElementAPI/issues/comments/243243643","html_url":"https://github.com/pixelandtonic/ElementAPI/pull/12#issuecomment-243243643","issue_url":"https://api.github.com/repos/pixelandtonic/ElementAPI/issues/12","id":243243643,"user":{"login":"AugustMiller","id":1895522,"avatar_url":"https://avatars.githubusercontent.com/u/1895522?v=3","gravatar_id":"","url":"https://api.github.com/users/AugustMiller","html_url":"https://github.com/AugustMiller","followers_url":"https://api.github.com/users/AugustMiller/followers","following_url":"https://api.github.com/users/AugustMiller/following{/other_user}","gists_url":"https://api.github.com/users/AugustMiller/gists{/gist_id}","starred_url":"https://api.github.com/users/AugustMiller/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AugustMiller/subscriptions","organizations_url":"https://api.github.com/users/AugustMiller/orgs","repos_url":"https://api.github.com/users/AugustMiller/repos","events_url":"https://api.github.com/users/AugustMiller/events{/privacy}","received_events_url":"https://api.github.com/users/AugustMiller/received_events","type":"User","site_admin":false},"created_at":"2016-08-29T20:22:35Z","updated_at":"2016-08-29T20:22:35Z","body":"Just a quick update, for those who may be curious— I've had this fork running in a [production environment](https://portlandstreetcar.org/) for a couple of months now, handling a number of queries from a widget that requests a particular ElementAPI endpoint immediately after page load.\r\n\r\nCan't point to any particular server load decrease, but it hasn't blown up yet. ;)"}}
{"actor":{"display_login":"AugustMiller"}}