From 0d83ed4b8bf4b099a250b4ef02bdaf78d5a595e3 Mon Sep 17 00:00:00 2001 From: QWp6t Date: Tue, 6 Dec 2016 03:28:41 -0800 Subject: [PATCH] Refactor Blade implementation. Use Container --- CHANGELOG.md | 1 + composer.json | 3 +- composer.lock | 58 +++++++- index.php | 2 +- src/filters.php | 64 ++------- src/helpers.php | 52 ++++--- src/lib/Sage/Asset.php | 39 ------ src/lib/Sage/Assets/JsonManifest.php | 18 ++- src/lib/Sage/Assets/ManifestInterface.php | 15 +- src/lib/Sage/Container.php | 10 ++ src/lib/Sage/Template/BladeProvider.php | 80 +++++++++++ src/lib/Sage/Template/ViewServiceProvider.php | 132 ------------------ src/setup.php | 31 ++++ templates/partials/page-header.blade.php | 2 +- 14 files changed, 250 insertions(+), 257 deletions(-) delete mode 100644 src/lib/Sage/Asset.php create mode 100644 src/lib/Sage/Container.php create mode 100644 src/lib/Sage/Template/BladeProvider.php delete mode 100644 src/lib/Sage/Template/ViewServiceProvider.php diff --git a/CHANGELOG.md b/CHANGELOG.md index fe2fc51..845ca2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ### HEAD +* Add Blade ([#1765](https://github.com/roots/sage/pull/1765)) * Remove sidebar defaults ([#1760](https://github.com/roots/sage/pull/1760)) * Remove post formats ([#1759](https://github.com/roots/sage/pull/1759)) diff --git a/composer.json b/composer.json index a38b260..7de0f37 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,8 @@ "require": { "php": ">=5.6.4", "composer/installers": "~1.0", - "illuminate/view": "^5.3" + "illuminate/view": "^5.3", + "jenssegers/blade": "dev-master#59ba2cc" }, "require-dev": { "squizlabs/php_codesniffer": "^2.5.1", diff --git a/composer.lock b/composer.lock index e628c58..52b86a2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "255f61d85f71037ef5fc7872e31015f1", - "content-hash": "a1a2a4510be5494654cdd98e6308e48e", + "hash": "91797de2d3afdfa1a932e8c0dfe808fe", + "content-hash": "b772c090cb59fb89a2df691ecd1ffe98", "packages": [ { "name": "composer/installers", @@ -466,6 +466,54 @@ "homepage": "https://laravel.com", "time": "2016-10-24 18:18:15" }, + { + "name": "jenssegers/blade", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/jenssegers/blade.git", + "reference": "59ba2cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jenssegers/blade/zipball/59ba2cc", + "reference": "59ba2cc", + "shasum": "" + }, + "require": { + "illuminate/view": "^5.1" + }, + "require-dev": { + "mockery/mockery": "^0.9", + "phpunit/phpunit": "^4.0|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jenssegers\\Blade\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jens Segers", + "homepage": "https://jenssegers.com" + } + ], + "description": "The standalone version of Laravel's Blade templating engine for use outside of Laravel.", + "keywords": [ + "blade", + "laravel", + "render", + "template", + "view" + ], + "time": "2016-08-23 11:51:53" + }, { "name": "paragonie/random_compat", "version": "v2.0.4", @@ -1023,11 +1071,13 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "jenssegers/blade": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.5.0" + "php": ">=5.6.4" }, "platform-dev": [] } diff --git a/index.php b/index.php index 1ae695e..d8704e2 100644 --- a/index.php +++ b/index.php @@ -1,3 +1,3 @@ classes */ @@ -33,62 +29,28 @@ add_filter('excerpt_more', function () { }); /** - * Use Blade template engine + * Template Hierarchy should search for .blade.php files */ array_map(function ($tag) { - add_filter("{$tag}_template_hierarchy", function($templates) { + add_filter("{$tag}_template_hierarchy", function ($templates) { return array_merge(str_replace('.php', '.blade.php', $templates), $templates); }); }, [ 'index', '404', 'archive', 'author', 'category', 'tag', 'taxonomy', 'date', 'home', 'front_page', 'page', 'paged', 'search', 'single', 'singular', 'attachment' ]); + +/** + * Render page using Blade + */ add_filter('template_include', function ($template) { - $blade_template = (!strpos($template, '.blade.php')) ? str_replace('.php', '.blade.php', $template) : $template; - $blade_template = locate_template(basename($blade_template)); + echo template($template); - if (!file_exists($blade_template)) { - return $template; - } - - $container = Container::getInstance(); - - $container->singleton('files', function () { - return new Filesystem; - }); - - $provider = new ViewServiceProvider($container); - $provider->register(); - - $template_engine = $container->make('view'); - - $template_name = basename(str_replace('.blade', '', $blade_template)); - $template_name = str_replace('.php', '', $template_name); - $html = $template_engine->make($template_name, apply_filters('laravel/blade/template_data', []))->render(); - - if (!$html) { - return $template; - } - - echo $html; - - return false; + // Return a blank file to make WordPress happy + return get_template_directory() . '/index.php'; }, 1000); -add_filter('comments_template', function ($theme_template) { - $container = Container::getInstance(); - $template_engine = $container->make('view'); - - $template_name = basename(str_replace('.blade.php', '', $theme_template)); - $html = $template_engine->make('partials/'.$template_name, []); - var_dump($template_engine->exists('partials/'.$template_name)); - $engine = $html->getEngine(); - $compiler = $engine->getCompiler(); - $template = $compiler->getCompiledPath($compiler->getPath()); - - if ($compiler->isExpired($template)) { - $compiler->compile($theme_template); - } - - return $template; -}); +/** + * Tell WordPress how to find the compiled path of comments.blade.php + */ +add_filter('comments_template', 'App\\template_path'); diff --git a/src/helpers.php b/src/helpers.php index db3c2c3..304d786 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -2,30 +2,50 @@ namespace App; -use Roots\Sage\Asset; -use Roots\Sage\Assets\JsonManifest; -use Roots\Sage\Template; +use Roots\Sage\Container; -function template($layout = 'base') +/** + * @param string $name + * @return Container|mixed + */ +function sage($name = '') { - return Template::$instances[$layout]; -} - -function template_part($template, array $context = [], $layout = 'base') -{ - extract($context); - include template($layout)->partial($template); + static $container; + if (!$container) { + $container = new Container; + } + return $name ? (isset($container[$name]) ? $container[$name] : $container["sage.{$name}"]) : $container; } /** - * @param $filename + * + * @param string $file + * @param array $data * @return string */ -function asset_path($filename) +function template($file, $data = []) { - static $manifest; - isset($manifest) || $manifest = new JsonManifest(get_stylesheet_directory() . '/' . Asset::$dist . '/assets.json'); - return (string) new Asset($filename, $manifest); + return sage('blade')->render($file, $data); +} + +/** + * Retrieve path to a compiled blade view + * @param $file + * @param array $data + * @return string + */ +function template_path($file, $data = []) +{ + return sage('blade')->compiledPath($file, $data); +} + +/** + * @param $asset + * @return string + */ +function asset_path($asset) +{ + return sage('assets')->getUri($asset); } /** diff --git a/src/lib/Sage/Asset.php b/src/lib/Sage/Asset.php deleted file mode 100644 index aeee9cc..0000000 --- a/src/lib/Sage/Asset.php +++ /dev/null @@ -1,39 +0,0 @@ -manifest = $manifest; - $this->asset = $file; - } - - public function __toString() - { - return $this->getUri(); - } - - public function getUri() - { - $file = ($this->manifest ? $this->manifest->get($this->asset) : $this->asset); - return get_template_directory_uri() . self::$dist . "/$file"; - } -} diff --git a/src/lib/Sage/Assets/JsonManifest.php b/src/lib/Sage/Assets/JsonManifest.php index a7835fa..37e5839 100644 --- a/src/lib/Sage/Assets/JsonManifest.php +++ b/src/lib/Sage/Assets/JsonManifest.php @@ -10,26 +10,32 @@ namespace Roots\Sage\Assets; class JsonManifest implements ManifestInterface { /** @var array */ - protected $manifest = []; + public $manifest; + + /** @var string */ + public $dist; /** * JsonManifest constructor + * * @param string $manifestPath Local filesystem path to JSON-encoded manifest + * @param string $distUri Remote URI to assets root */ - public function __construct($manifestPath) + public function __construct($manifestPath, $distUri) { $this->manifest = file_exists($manifestPath) ? json_decode(file_get_contents($manifestPath), true) : []; + $this->dist = $distUri; } /** @inheritdoc */ - public function get($file) + public function get($asset) { - return isset($this->manifest[$file]) ? $this->manifest[$file] : $file; + return isset($this->manifest[$asset]) ? $this->manifest[$asset] : $asset; } /** @inheritdoc */ - public function getAll() + public function getUri($asset) { - return $this->manifest; + return "{$this->dist}/{$this->get($asset)}"; } } diff --git a/src/lib/Sage/Assets/ManifestInterface.php b/src/lib/Sage/Assets/ManifestInterface.php index e2583af..a1542ee 100644 --- a/src/lib/Sage/Assets/ManifestInterface.php +++ b/src/lib/Sage/Assets/ManifestInterface.php @@ -12,17 +12,20 @@ interface ManifestInterface /** * Get the cache-busted filename * - * If the manifest does not have an entry for $file, then return $file + * If the manifest does not have an entry for $asset, then return $asset * - * @param string $file The original name of the file before cache-busting + * @param string $asset The original name of the file before cache-busting * @return string */ - public function get($file); + public function get($asset); /** - * Get the asset manifest + * Get the cache-busted URI * - * @return array + * If the manifest does not have an entry for $asset, then return URI for $asset + * + * @param string $asset The original name of the file before cache-busting + * @return string */ - public function getAll(); + public function getUri($asset); } diff --git a/src/lib/Sage/Container.php b/src/lib/Sage/Container.php new file mode 100644 index 0000000..c015e24 --- /dev/null +++ b/src/lib/Sage/Container.php @@ -0,0 +1,10 @@ +container['view']->make($this->normalizeViewPath($view), $data, $mergeData); + } + + /** + * @param string $view + * @param array $data + * @param array $mergeData + * @return string + */ + public function render($view, $data = [], $mergeData = []) + { + return $this->make($view, $data, $mergeData)->render(); + } + + /** + * @param string $file + * @param array $data + * @param array $mergeData + * @return string + */ + public function compiledPath($file, $data = [], $mergeData = []) + { + $rendered = $this->make($file, $data, $mergeData); + $engine = $rendered->getEngine(); + + if (!($engine instanceof CompilerEngine)) { + // Using PhpEngine, so just return the file + return $file; + } + + $compiler = $engine->getCompiler(); + $compiledPath = $compiler->getCompiledPath($rendered->getPath()); + if ($compiler->isExpired($compiledPath)) { + $compiler->compile($file); + } + return $compiledPath; + } + + /** + * @param string $file + * @return string + */ + public function normalizeViewPath($file) + { + // Convert `\` to `/` + $view = str_replace('\\', '/', $file); + + // Remove unnecessary parts of the path + $view = str_replace(array_merge((array) $this->viewPaths, ['.blade.php', '.php']), '', $view); + + // Remove leading slashes + $view = ltrim($view, '/'); + + // Convert `/` to `.` + return str_replace('/', '.', $view); + } +} diff --git a/src/lib/Sage/Template/ViewServiceProvider.php b/src/lib/Sage/Template/ViewServiceProvider.php deleted file mode 100644 index 50ecc6f..0000000 --- a/src/lib/Sage/Template/ViewServiceProvider.php +++ /dev/null @@ -1,132 +0,0 @@ -registerEngineResolver(); - - $this->registerViewFinder(); - - $this->registerFactory(); - } - - /** - * Register the engine resolver instance. - * - * @return void - */ - public function registerEngineResolver() - { - $this->app->singleton('view.engine.resolver', function () { - $resolver = new EngineResolver; - - // Next we will register the various engines with the resolver so that the - // environment can resolve the engines it needs for various views based - // on the extension of view files. We call a method for each engines. - foreach (['php', 'blade'] as $engine) { - $this->{'register'.ucfirst($engine).'Engine'}($resolver); - } - - return $resolver; - }); - } - - /** - * Register the PHP engine implementation. - * - * @param \Illuminate\View\Engines\EngineResolver $resolver - * @return void - */ - public function registerPhpEngine($resolver) - { - $resolver->register('php', function () { - return new PhpEngine; - }); - } - - /** - * Register the Blade engine implementation. - * - * @param \Illuminate\View\Engines\EngineResolver $resolver - * @return void - */ - public function registerBladeEngine($resolver) - { - $app = $this->app; - - // The Compiler engine requires an instance of the CompilerInterface, which in - // this case will be the Blade compiler, so we'll first create the compiler - // instance to pass into the engine so it can compile the views properly. - $app->singleton('blade.compiler', function ($app) { - $cache = apply_filters('roots/views/blade/compiled_path', wp_upload_dir()['basedir'] . '/cache/compiled'); - if (!file_exists($cache)) { - wp_mkdir_p($cache); - } - - return new BladeCompiler($app->make('Illuminate\\Filesystem\\Filesystem'), $cache); - }); - - $resolver->register('blade', function () use ($app) { - return new CompilerEngine($app['blade.compiler']); - }); - } - - /** - * Register the view finder implementation. - * - * @return void - */ - public function registerViewFinder() - { - $this->app->bind('view.finder', function ($app) { - $paths = apply_filters('roots/views/blade/template_directories', [TEMPLATEPATH]); - - return new FileViewFinder($app['files'], $paths); - }); - } - - /** - * Register the view environment. - * - * @return void - */ - public function registerFactory() - { - $this->app->singleton('view', function ($app) { - // Next we need to grab the engine resolver instance that will be used by the - // environment. The resolver will be used by an environment to get each of - // the various engine implementations such as plain PHP or Blade engine. - $resolver = $app['view.engine.resolver']; - - $finder = $app['view.finder']; - - $env = new Factory($resolver, $finder, new Dispatcher($app)); - - // We will also set the container instance on this view environment since the - // view composers may be classes registered in the container, which allows - // for great testable, flexible composers for the application developer. - $env->setContainer($app); - - $env->share('app', $app); - - return $env; - }); - } -} diff --git a/src/setup.php b/src/setup.php index 0661100..2b3b9ee 100644 --- a/src/setup.php +++ b/src/setup.php @@ -2,6 +2,37 @@ namespace App; +use Roots\Sage\Assets\JsonManifest; +use Roots\Sage\Template\BladeProvider; + +/** + * Add JsonManifest to Sage container + */ +sage()->singleton('sage.assets', function () { + return new JsonManifest( + get_stylesheet_directory().'/dist/assets.json', + get_stylesheet_directory_uri().'/dist' + ); +}); + +/** + * Add Blade to Sage container + */ +sage()->singleton('sage.blade', function () { + $cachePath = wp_upload_dir()['basedir'].'/cache/compiled'; + if (!file_exists($cachePath)) { + wp_mkdir_p($cachePath); + } + return new BladeProvider(TEMPLATEPATH, $cachePath, sage()); +}); + +/** + * Create @asset() Blade directive + */ +sage('blade')->compiler()->directive('asset', function ($asset) { + return ''; +}); + /** * Theme assets */ diff --git a/templates/partials/page-header.blade.php b/templates/partials/page-header.blade.php index 9e1a4c5..e60521f 100644 --- a/templates/partials/page-header.blade.php +++ b/templates/partials/page-header.blade.php @@ -1,3 +1,3 @@