{"action":"created","issue":{"url":"https://api.github.com/repos/timber/timber/issues/1254","repository_url":"https://api.github.com/repos/timber/timber","labels_url":"https://api.github.com/repos/timber/timber/issues/1254/labels{/name}","comments_url":"https://api.github.com/repos/timber/timber/issues/1254/comments","events_url":"https://api.github.com/repos/timber/timber/issues/1254/events","html_url":"https://github.com/timber/timber/pull/1254","id":192012903,"number":1254,"title":"Unable to add custom twig loaders","user":{"login":"adamtomat","id":2631499,"avatar_url":"https://avatars.githubusercontent.com/u/2631499?v=3","gravatar_id":"","url":"https://api.github.com/users/adamtomat","html_url":"https://github.com/adamtomat","followers_url":"https://api.github.com/users/adamtomat/followers","following_url":"https://api.github.com/users/adamtomat/following{/other_user}","gists_url":"https://api.github.com/users/adamtomat/gists{/gist_id}","starred_url":"https://api.github.com/users/adamtomat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/adamtomat/subscriptions","organizations_url":"https://api.github.com/users/adamtomat/orgs","repos_url":"https://api.github.com/users/adamtomat/repos","events_url":"https://api.github.com/users/adamtomat/events{/privacy}","received_events_url":"https://api.github.com/users/adamtomat/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2016-11-28T13:59:59Z","updated_at":"2016-12-02T01:14:11Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/timber/timber/pulls/1254","html_url":"https://github.com/timber/timber/pull/1254","diff_url":"https://github.com/timber/timber/pull/1254.diff","patch_url":"https://github.com/timber/timber/pull/1254.patch"},"body":"**Ticket**: https://github.com/timber/timber/issues/1253\r\n\r\n#### Issue\r\nUnable to add custom twig loaders.\r\n\r\n\r\n#### Solution\r\nAdd a new filter (hook), that exposes the `Twig_Loader_filesystem` that TImber creates. This allows theme developers to modify this or add their own loader and create a new [loader chain](http://twig.sensiolabs.org/doc/api.html#twig-loader-chain).\r\n\r\n\r\n#### Impact\r\nThis fix is additive, and therefore should be backwards compatible. It's also possible that developers could not return the correct thing in the filter which could cause unexpected behaviour. I'm not sure there's much value in trying to defend against this though.\r\n\r\n#### Usage\r\nAn example use case:\r\n\r\n```php\r\nnamespace App;\r\n\r\n// Hook into when Timber initialises the Twig_Loader_Filesystem\r\nadd_filter('timber/loader/loader', function ($loader) {\r\n    $customLoader = new \\App\\CustomLoader(get_stylesheet_directory() . '/views');\r\n    // Add our loader to the end of the chain (i.e. Timber does its lookup, then runs ours)\r\n    $chainLoader = new \\Twig_Loader_Chain([$loader, $customLoader]);\r\n\r\n    return $chainLoader;\r\n});\r\n\r\nclass CustomLoader implements \\Twig_LoaderInterface\r\n{\r\n    // Base path for patterns lib.\r\n    protected $patternsPath;\r\n\r\n    public function __construct($patternsPath)\r\n    {\r\n        $this->patternsPath = $patternsPath;\r\n    }\r\n\r\n    /**\r\n     * Gets the source code of a template, given its name.\r\n     *\r\n     * @param  string $name string The name of the template to load\r\n     *\r\n     * @return string The template source code\r\n     */\r\n    public function getSource($name)\r\n    {\r\n\r\n        // Remove the extension at this point as we add it ourselves below\r\n        $id = preg_replace('/\\.twig$/', '', $name);\r\n\r\n        // Add template.twig into path\r\n        $path = $this->patternsPath . '/' . $id . '/template.twig';\r\n\r\n        return file_get_contents($path);\r\n    }\r\n\r\n    /**\r\n     * Gets the cache key to use for the cache for a given template name.\r\n     *\r\n     * @param  string $name string The name of the template to load\r\n     *\r\n     * @return string The cache key\r\n     */\r\n    public function getCacheKey($name)\r\n    {\r\n        return md5($name);\r\n    }\r\n\r\n    /**\r\n     * Returns true if the template is still fresh.\r\n     *\r\n     * @param string    $name The template name\r\n     * @param timestamp $time The last modification time of the cached template\r\n     */\r\n    public function isFresh($name, $time)\r\n    {\r\n        return true;\r\n    }\r\n}\r\n```\r\n\r\n\r\n#### Considerations\r\nThis solution simply exposes the loader, which allows people to do a lot more. Another approach may be to let Timber handle the `Twig_Loader_Chain` and just expose an `addLoader()` method or something similar. However, that feels less flexible and scaleable.\r\n\r\n\r\n#### Testing\r\nSorry, no tests written. An example test could be something like:\r\n\r\n```php\r\nfunction testTwigLoaderFilter () {\r\n    $php_unit = $this;\r\n    add_filter('timber/loader/loader', function ($loader) use ($php_unit) {\r\n        $php_unit->assertInstanceOf('Twig_Loader_Filesystem', $loader);\r\n    });\r\n    $str = Timber::compile('assets/single.twig', array());\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/timber/timber/issues/comments/264345698","html_url":"https://github.com/timber/timber/pull/1254#issuecomment-264345698","issue_url":"https://api.github.com/repos/timber/timber/issues/1254","id":264345698,"user":{"login":"jarednova","id":1298086,"avatar_url":"https://avatars.githubusercontent.com/u/1298086?v=3","gravatar_id":"","url":"https://api.github.com/users/jarednova","html_url":"https://github.com/jarednova","followers_url":"https://api.github.com/users/jarednova/followers","following_url":"https://api.github.com/users/jarednova/following{/other_user}","gists_url":"https://api.github.com/users/jarednova/gists{/gist_id}","starred_url":"https://api.github.com/users/jarednova/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jarednova/subscriptions","organizations_url":"https://api.github.com/users/jarednova/orgs","repos_url":"https://api.github.com/users/jarednova/repos","events_url":"https://api.github.com/users/jarednova/events{/privacy}","received_events_url":"https://api.github.com/users/jarednova/received_events","type":"User","site_admin":false},"created_at":"2016-12-02T01:14:11Z","updated_at":"2016-12-02T01:14:11Z","body":"@adamtomat Thanks for the PR! I'm sympathetic to the idea that `timber/loader/filesystem` is much prettier, but given your reasoning and @mahagr's, it makes sense that _accuracy_ is the most crucial guiding factor at this \"deep\" level. Merged!"}}
{"actor":{"display_login":"jarednova"}}