diff --git a/CHANGELOG.md b/CHANGELOG.md index 845ca2c7cc..41623fdb5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ### HEAD -* Add Blade ([#1765](https://github.com/roots/sage/pull/1765)) +* Add Blade ([#1765](https://github.com/roots/sage/pull/1765) and [#1777](https://github.com/roots/sage/pull/1777)) * Remove sidebar defaults ([#1760](https://github.com/roots/sage/pull/1760)) * Remove post formats ([#1759](https://github.com/roots/sage/pull/1759)) @@ -7,13 +7,13 @@ * Use new webpack api schema ([8ac5f15](https://github.com/roots/sage/commit/e6e60aa)) * Update dependencies ([70ebba7](https://github.com/roots/sage/commit/70ebba7)) * Variables organization ([8ac5f15](https://github.com/roots/sage/commit/8ac5f15)) -* Use $.fn.ready() (reverts 724d550) ([e7fccbe](https://github.com/roots/sage/commit/e7fccbe)) +* Use `$.fn.ready()` (reverts [724d550](https://github.com/roots/sage/commit/724d550)) ([e7fccbe](https://github.com/roots/sage/commit/e7fccbe)) * Theme activation updates 'stylesheet' option instead of 'template' ([fb19145](https://github.com/roots/sage/commit/fb19145)) * Reorganize and refactor build routine ([8c9ba05](https://github.com/roots/sage/commit/8c9ba05)) * Switch assets manifest plugin ([c1bb2b3](https://github.com/roots/sage/commit/c1bb2b3)) * Add images to assets manifest ([c49793c](https://github.com/roots/sage/commit/c49793c)) * Switch from babel to buble ([0d38ab8](https://github.com/roots/sage/commit/0d38ab8)) -* Update dependencies & webpack compatibility (BREAKING CHANGES) ([eae52fd](https://github.com/roots/sage/commit/eae52fd)) +* Update dependencies & webpack compatibility ([eae52fd](https://github.com/roots/sage/commit/eae52fd)) * Use http by default (not https) to be consistent with Trellis ([e6f2f49](https://github.com/roots/sage/commit/e6f2f49)) ### 9.0.0-alpha.3: September 11th, 2016 diff --git a/composer.json b/composer.json index e2a74954f9..8896ae7c34 100644 --- a/composer.json +++ b/composer.json @@ -31,8 +31,7 @@ "require": { "php": ">=5.6.4", "composer/installers": "~1.0", - "illuminate/view": "~5.3.0", - "jenssegers/blade": "dev-master#59ba2cc" + "illuminate/view": "~5.3.0" }, "require-dev": { "squizlabs/php_codesniffer": "^2.5.1", diff --git a/composer.lock b/composer.lock index a1cc4c5382..33c77f679d 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": "6ad0fe16faf42536bd505456465e7159", - "content-hash": "bd5656c1e6d09224c276679d556f6ed1", + "hash": "2fe2f9807abba61c265ec0afe9059117", + "content-hash": "3d29aea6e725e8821f18f7f1a088d663", "packages": [ { "name": "composer/installers", @@ -466,54 +466,6 @@ "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", @@ -611,7 +563,7 @@ }, { "name": "symfony/debug", - "version": "v3.1.7", + "version": "v3.1.8", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", @@ -668,16 +620,16 @@ }, { "name": "symfony/finder", - "version": "v3.1.7", + "version": "v3.1.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9925935bf7144f9e4d2b976905881b4face036fb" + "reference": "74dcd370c8d057882575e535616fde935e411b19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9925935bf7144f9e4d2b976905881b4face036fb", - "reference": "9925935bf7144f9e4d2b976905881b4face036fb", + "url": "https://api.github.com/repos/symfony/finder/zipball/74dcd370c8d057882575e535616fde935e411b19", + "reference": "74dcd370c8d057882575e535616fde935e411b19", "shasum": "" }, "require": { @@ -713,7 +665,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-11-03 08:04:31" + "time": "2016-12-13 09:38:21" } ], "packages-dev": [ @@ -902,16 +854,16 @@ }, { "name": "symfony/config", - "version": "v3.2.0", + "version": "v3.2.1", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "4a68f8953180bf77ea65f585020f4db0b18600b4" + "reference": "b4ec9f099599cfc5b7f4d07bb2e910781a2be5e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/4a68f8953180bf77ea65f585020f4db0b18600b4", - "reference": "4a68f8953180bf77ea65f585020f4db0b18600b4", + "url": "https://api.github.com/repos/symfony/config/zipball/b4ec9f099599cfc5b7f4d07bb2e910781a2be5e4", + "reference": "b4ec9f099599cfc5b7f4d07bb2e910781a2be5e4", "shasum": "" }, "require": { @@ -954,20 +906,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-11-29 11:12:32" + "time": "2016-12-09 07:45:17" }, { "name": "symfony/dependency-injection", - "version": "v3.2.0", + "version": "v3.2.1", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "f5419adad083c90e0dfd8588ef83683d7dbcc20d" + "reference": "037054501c41007c93b6de1b5c7a7acb83523593" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f5419adad083c90e0dfd8588ef83683d7dbcc20d", - "reference": "f5419adad083c90e0dfd8588ef83683d7dbcc20d", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/037054501c41007c93b6de1b5c7a7acb83523593", + "reference": "037054501c41007c93b6de1b5c7a7acb83523593", "shasum": "" }, "require": { @@ -1017,11 +969,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-11-25 12:32:42" + "time": "2016-12-08 15:27:33" }, { "name": "symfony/filesystem", - "version": "v3.2.0", + "version": "v3.2.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -1071,9 +1023,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "jenssegers/blade": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/src/filters.php b/src/filters.php index 187400b3c4..4da33c22fe 100644 --- a/src/filters.php +++ b/src/filters.php @@ -34,7 +34,7 @@ array_map(function ($type) { add_filter("{$type}_template_hierarchy", function ($templates) { return call_user_func_array('array_merge', array_map(function ($template) { - $normalizedTemplate = str_replace('.', '/', sage('blade')->normalizeViewPath($template)); + $normalizedTemplate = preg_replace('%(\.blade)?(\.php)?$%', '', $template); return ["{$normalizedTemplate}.blade.php", "{$normalizedTemplate}.php"]; }, $templates)); }); @@ -47,11 +47,14 @@ * Render page using Blade */ add_filter('template_include', function ($template) { - echo template($template, apply_filters('sage/template_data', [])); + $data = array_reduce(get_body_class(), function ($data, $class) { + return apply_filters("sage/template/{$class}/data", $data); + }, []); + echo template($template, $data); // Return a blank file to make WordPress happy return get_template_directory() . '/index.php'; -}, 1000); +}, PHP_INT_MAX); /** * Tell WordPress how to find the compiled path of comments.blade.php diff --git a/src/lib/Sage/Template/Blade.php b/src/lib/Sage/Template/Blade.php new file mode 100644 index 0000000000..1e25b2e707 --- /dev/null +++ b/src/lib/Sage/Template/Blade.php @@ -0,0 +1,129 @@ +env = $env; + $this->app = $app; + } + + /** + * Get the compiler + * + * @return \Illuminate\View\Compilers\BladeCompiler + */ + public function compiler() + { + static $engineResolver; + if (!$engineResolver) { + $engineResolver = $this->app->make('view.engine.resolver'); + } + return $engineResolver->resolve('blade')->getCompiler(); + } + + /** + * @param string $view + * @param array $data + * @param array $mergeData + * @return string + */ + public function render($view, $data = [], $mergeData = []) + { + /** @var \Illuminate\Contracts\Filesystem\Filesystem $filesystem */ + $filesystem = $this->app['files']; + return $this->{$filesystem->exists($view) ? 'file' : 'make'}($view, $data, $mergeData)->render(); + } + + /** + * @param string $file + * @param array $data + * @param array $mergeData + * @return string + */ + public function compiledPath($file, $data = [], $mergeData = []) + { + $rendered = $this->file($file, $data, $mergeData); + /** @var EngineInterface $engine */ + $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); + + // Add namespace to path if necessary + $view = $this->applyNamespaceToPath($view); + + // Remove unnecessary parts of the path + $view = str_replace(array_merge($this->app['config']['view.paths'], ['.blade.php', '.php']), '', $view); + + // Remove superfluous and leading slashes + return ltrim(preg_replace('%//+%', '/', $view), '/'); + } + + /** + * Convert path to view namespace + * @param string $path + * @return string + */ + public function applyNamespaceToPath($path) + { + /** @var ViewFinderInterface $finder */ + $finder = $this->app['view.finder']; + if (!method_exists($finder, 'getHints')) { + return $path; + } + $delimiter = $finder::HINT_PATH_DELIMITER; + $hints = $finder->getHints(); + $view = array_reduce(array_keys($hints), function ($view, $namespace) use ($delimiter, $hints) { + return str_replace($hints[$namespace], $namespace.$delimiter, $view); + }, $path); + return preg_replace("%{$delimiter}[\\/]*%", $delimiter, $view); + } + + /** + * Pass any method to the view Factory instance. + * + * @param string $method + * @param array $params + * @return mixed + */ + public function __call($method, $params) + { + return call_user_func_array([$this->env, $method], $params); + } +} diff --git a/src/lib/Sage/Template/BladeProvider.php b/src/lib/Sage/Template/BladeProvider.php index 02751d75dd..40d59b443d 100644 --- a/src/lib/Sage/Template/BladeProvider.php +++ b/src/lib/Sage/Template/BladeProvider.php @@ -2,108 +2,93 @@ namespace Roots\Sage\Template; -use Jenssegers\Blade\Blade; -use Illuminate\View\Engines\CompilerEngine; +use Illuminate\Container\Container; use Illuminate\Contracts\Container\Container as ContainerContract; - -class BladeProvider extends Blade +use Illuminate\Events\Dispatcher; +use Illuminate\Filesystem\Filesystem; +use Illuminate\View\ViewServiceProvider; + +/** + * Class BladeProvider + */ +class BladeProvider extends ViewServiceProvider { - /** @var Blade */ - public $blade; - - /** @var string */ - protected $cachePath; - /** - * Constructor. - * - * @param array $viewPaths - * @param string $cachePath * @param ContainerContract $container + * @param array $config */ - public function __construct($viewPaths, $cachePath, ContainerContract $container = null) + public function __construct(ContainerContract $container = null, $config = []) { - parent::__construct((array) $viewPaths, $cachePath, $container); - $this->registerViewFinder(); + /** @noinspection PhpParamsInspection */ + parent::__construct($container ?: new Container); + + $this->app->bindIf('config', function () use ($config) { + return $config; + }, true); } /** - * @param string $view - * @param array $data - * @param array $mergeData - * @return \Illuminate\View\View + * Bind required instances for the service provider. */ - public function make($view, $data = [], $mergeData = []) + public function register() { - return $this->container['view']->make($this->normalizeViewPath($view), $data, $mergeData); + $this->registerFilesystem(); + $this->registerEvents(); + $this->registerEngineResolver(); + $this->registerViewFinder(); + $this->registerFactory(); + return $this; } /** - * @param string $view - * @param array $data - * @param array $mergeData - * @return string + * Register Filesystem */ - public function render($view, $data = [], $mergeData = []) + public function registerFilesystem() { - return $this->make($view, $data, $mergeData)->render(); + $this->app->bindIf('files', function () { + return new Filesystem; + }, true); + return $this; } /** - * @param string $file - * @param array $data - * @param array $mergeData - * @return string + * Register the events dispatcher */ - public function compiledPath($file, $data = [], $mergeData = []) + public function registerEvents() { - $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; + $this->app->bindIf('events', function () { + return new Dispatcher; + }, true); + return $this; } - /** - * Register the view finder implementation. - * - * @return void - */ - public function registerViewFinder() + /** @inheritdoc */ + public function registerEngineResolver() { - $this->container->bind('view.finder', function ($app) { - $paths = $app['config']['view.paths']; + parent::registerEngineResolver(); + return $this; + } - return new FileViewFinder($app['files'], $paths); - }); + /** @inheritdoc */ + public function registerFactory() + { + parent::registerFactory(); + return $this; } /** - * @param string $file - * @return string + * Register the view finder implementation. */ - public function normalizeViewPath($file) + public function registerViewFinder() { - // Convert `\` to `/` - $view = str_replace('\\', '/', $file); - - // Remove unnecessary parts of the path - $remove = array_merge($this->viewPaths, array_map('basename', $this->viewPaths), ['.blade.php', '.php']); - $view = str_replace($remove, '', $view); - - // Remove leading slashes - $view = ltrim($view, '/'); - - // Convert `/` to `.` - return str_replace('/', '.', $view); + $this->app->bindIf('view.finder', function ($app) { + $config = $this->app['config']; + $paths = $config['view.paths']; + $namespaces = $config['view.namespaces']; + $finder = new FileViewFinder($app['files'], $paths); + array_map([$finder, 'addNamespace'], array_keys($namespaces), $namespaces); + return $finder; + }, true); + return $this; } } diff --git a/src/lib/Sage/Template/FileViewFinder.php b/src/lib/Sage/Template/FileViewFinder.php index e33cc21d3b..daadce7160 100644 --- a/src/lib/Sage/Template/FileViewFinder.php +++ b/src/lib/Sage/Template/FileViewFinder.php @@ -12,7 +12,7 @@ class FileViewFinder extends \Illuminate\View\FileViewFinder * @param string $name * @return array */ - protected function getPossibleViewFiles($name) + public function getPossibleViewFiles($name) { $parts = explode(self::FALLBACK_PARTS_DELIMITER, $name); $templates[] = array_shift($parts); diff --git a/src/setup.php b/src/setup.php index 2b3b9eec20..63749ca2b7 100644 --- a/src/setup.php +++ b/src/setup.php @@ -3,36 +3,9 @@ namespace App; use Roots\Sage\Assets\JsonManifest; +use Roots\Sage\Template\Blade; 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 */ @@ -86,7 +59,7 @@ * @see assets/styles/layouts/_tinymce.scss */ add_editor_style(asset_path('styles/main.css')); -}); +}, 20); /** * Register sidebars @@ -107,3 +80,49 @@ 'id' => 'sidebar-footer' ] + $config); }); + +/** + * Setup Sage options + */ +add_action('after_setup_theme', function () { + /** + * Sage config + */ + sage()->bindIf('config', function () { + return [ + 'view.paths' => [TEMPLATEPATH, STYLESHEETPATH], + 'view.compiled' => wp_upload_dir()['basedir'].'/cache/compiled', + 'view.namespaces' => ['App' => WP_CONTENT_DIR], + 'assets.manifest' => get_stylesheet_directory().'/dist/assets.json', + 'assets.uri' => get_stylesheet_directory_uri().'/dist' + ]; + }); + + /** + * Add JsonManifest to Sage container + */ + sage()->singleton('sage.assets', function ($app) { + $config = $app['config']; + return new JsonManifest($config['assets.manifest'], $config['assets.uri']); + }); + + /** + * Add Blade to Sage container + */ + sage()->singleton('sage.blade', function ($app) { + $config = $app['config']; + $cachePath = $config['view.compiled']; + if (!file_exists($cachePath)) { + wp_mkdir_p($cachePath); + } + (new BladeProvider($app))->register(); + return new Blade($app['view'], $app); + }); + + /** + * Create @asset() Blade directive + */ + sage('blade')->compiler()->directive('asset', function ($asset) { + return ''; + }); +});