🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # Assets管理 `Phalcon\Assets` 是一个允许您在Web应用程序中管理静态资源(如CSS样式表或JavaScript库)的组件。 `Phalcon\Assets\Manager` 在服务容器中可用,因此您可以从容器可用的应用程序的任何部分添加资源。 ## 添加资源 Assets支持两种内置资源:CSS和JavaScripts。如果需要,您可以创建其他资源。资产管理器在内部存储两个默认资源集合 - 一个用于JavaScript,另一个用于CSS。 您可以轻松地向这些集合添加资源,如下所示: ```php <?php use Phalcon\Mvc\Controller; class IndexController extends Controller { public function index() { // Add some local CSS resources $this->assets->addCss('css/style.css'); $this->assets->addCss('css/index.css'); // And some local JavaScript resources $this->assets->addJs('js/jquery.js'); $this->assets->addJs('js/bootstrap.min.js'); } } ``` 然后在视图中,可以打印这些资源: ```php <html> <head> <title>Some amazing website</title> <?php $this->assets->outputCss(); ?> </head> <body> <!-- ... --> <?php $this->assets->outputJs(); ?> </body> <html> ``` Volt 语法: ```volt <html> <head> <title>Some amazing website</title> {{ assets.outputCss() }} </head> <body> <!-- ... --> {{ assets.outputJs() }} </body> <html> ``` 为了获得更好的页面加载性能,建议将JavaScript放在HTML的末尾而不是`<head>`。 ## 本地/远程资源 本地资源是由同一应用程序提供的资源,它们位于应用程序的文档根目录中。本地资源中的URL由`url`服务生成,通常为`Phalcon\Mvc\Url`。 远程资源是由[CDN](https://en.wikipedia.org/wiki/Content_delivery_network)提供的诸如[jQuery](https://jquery.com),[Bootstrap](http://www.bootcss.com/)等公共库的资源。 `addCss()`和`addJs()`的第二个参数表示资源是否为本地资源(true为local,false为remote)。默认情况下,Assets管理器将假定资源是本地的: ```php <?php public function indexAction() { // Add some remote CSS resources $this->assets->addCss('//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css', false); // Then add some local CSS resources $this->assets->addCss('css/style.css', true); $this->assets->addCss('css/extra.css'); } ``` ## 集合 集合组相同类型的资源。Assets管理器隐式创建两个集合:`css`和`js` 。您可以创建其他集合以对特定资源进行分组,以便更轻松地将这些资源放置在视图中: ```php <?php // Javascripts in the header $headerCollection = $this->assets->collection('header'); $headerCollection->addJs('js/jquery.js'); $headerCollection->addJs('js/bootstrap.min.js'); // Javascripts in the footer $footerCollection = $this->assets->collection('footer'); $footerCollection->addJs('js/jquery.js'); $footerCollection->addJs('js/bootstrap.min.js'); ``` 然后在视图中: ```php <html> <head> <title>Some amazing website</title> <?php $this->assets->outputJs('header'); ?> </head> <body> <!-- ... --> <?php $this->assets->outputJs('footer'); ?> </body> <html> ``` Volt语法: ```twig <html> <head> <title>Some amazing website</title> {{ assets.outputCss('header') }} </head> <body> <!-- ... --> {{ assets.outputJs('footer') }} </body> <html> ``` ## URL前缀 集合可以是URL前缀,这使您可以随时轻松地从一台服务器更改为另一台服务器: ```php <?php $footerCollection = $this->assets->collection('footer'); if ($config->environment === 'development') { $footerCollection->setPrefix('/'); } else { $footerCollection->setPrefix('http:://cdn.example.com/'); } $footerCollection->addJs('js/jquery.js'); $footerCollection->addJs('js/bootstrap.min.js'); ``` 链式语法也可用: ```php <?php $headerCollection = $assets ->collection('header') ->setPrefix('http://cdn.example.com/') ->setLocal(false) ->addJs('js/jquery.js') ->addJs('js/bootstrap.min.js'); ``` ## 压缩/过滤 `Phalcon\Assets` 提供JavaScript和CSS资源的内置压缩。您可以创建一组资源,指示Assets管理器必须过滤哪些资源以及必须保留哪些资源。 除此之外,[Douglas Crockford](http://www.crockford.com) 的 `Jsmin` 是核心扩展的一部分,提供JavaScript文件的缩小以获得最佳性能。 在CSS领域, [Ryan Day](https://github.com/soldair)的`CSSMin` 也可用于缩小CSS文件。 以下示例显示如何压缩资源集合: ```php <?php $manager // These JavaScripts are located in the page's bottom ->collection('jsFooter') // The name of the final output ->setTargetPath('final.js') // The script tag is generated with this URI ->setTargetUri('production/final.js') // This is a remote resource that does not need filtering ->addJs('code.jquery.com/jquery-1.10.0.min.js', false, false) // These are local resources that must be filtered ->addJs('common-functions.js') ->addJs('page-functions.js') // Join all the resources in a single file ->join(true) // Use the built-in Jsmin filter ->addFilter( new Phalcon\Assets\Filters\Jsmin() ) // Use a custom filter ->addFilter( new MyApp\Assets\Filters\LicenseStamper() ); ``` 集合可以包含JavaScript或CSS资源,但不能同时包含两者。某些资源可能是远程的,也就是说,它们是通过HTTP从远程源获取的,以便进一步过滤。建议将外部资源转换为本地资源以获得更好的性能。 如上所示, `addJs()` 方法用于向集合添加资源,第二个参数指示资源是否为外部资源,第三个参数指示资源是应该过滤还是保留原样: ```php <?php // These Javascripts are located in the page's bottom $jsFooterCollection = $manager->collection('jsFooter'); // This a remote resource that does not need filtering $jsFooterCollection->addJs('code.jquery.com/jquery-1.10.0.min.js', false, false); // These are local resources that must be filtered $jsFooterCollection->addJs('common-functions.js'); $jsFooterCollection->addJs('page-functions.js'); ``` 过滤器在集合中注册,允许多个过滤器,资源中的内容按照过滤器注册的顺序进行过滤: ```php <?php // Use the built-in Jsmin filter $jsFooterCollection->addFilter( new Phalcon\Assets\Filters\Jsmin() ); // Use a custom filter $jsFooterCollection->addFilter( new MyApp\Assets\Filters\LicenseStamper() ); ``` 请注意,内置和自定义过滤器都可以透明地应用于集合。最后一步是确定集合中的所有资源是否必须连接到单个文件中,或者单独为每个资源提供服务。要告诉集合必须连接所有资源,可以使用`join()` 方法。 如果要连接资源,我们还需要定义将用于存储资源的文件以及将用于显示资源的URI。使用`setTargetPath()``setTargetUri()`设置这些: ```php <?php $jsFooterCollection->join(true); // The name of the final file path $jsFooterCollection->setTargetPath('public/production/final.js'); // The script HTML tag is generated with this URI $jsFooterCollection->setTargetUri('production/final.js'); ``` ### 内置过滤器 Phalcon提供了2个内置过滤器来缩小JavaScript和CSS,它们的C-backend提供了执行此任务的最小开销: | 过滤器 |描述 | | ---------------------------------- | ------------------------------------------------------------------------------------------------------------ | | `Phalcon\Assets\Filters\Jsmin` | 通过删除Javascript解释器/编译器忽略的不必要的字符来压缩JavaScript| | `Phalcon\Assets\Filters\Cssmin` |通过删除已被浏览器忽略的不必要字符来压缩CSS | ### 自定义过滤器 除了内置过滤器,您还可以创建自己的过滤器。这些可以利用现有的和更高级的工具,如[YUI](http://yui.github.io/yuicompressor/),[Sass](http://sass-lang.com/),[Closure](https://developers.google.com/closure/compiler/)等: ```php <?php use Phalcon\Assets\FilterInterface; /** * Filters CSS content using YUI * * @param string $contents * @return string */ class CssYUICompressor implements FilterInterface { protected $options; /** * CssYUICompressor constructor * * @param array $options */ public function __construct(array $options) { $this->options = $options; } /** * Do the filtering * * @param string $contents * * @return string */ public function filter($contents) { // Write the string contents into a temporal file file_put_contents('temp/my-temp-1.css', $contents); system( $this->options['java-bin'] . ' -jar ' . $this->options['yui'] . ' --type css ' . 'temp/my-temp-file-1.css ' . $this->options['extra-options'] . ' -o temp/my-temp-file-2.css' ); // Return the contents of file return file_get_contents('temp/my-temp-file-2.css'); } } ``` 用法: ```php <?php // Get some CSS collection $css = $this->assets->get('head'); // Add/Enable the YUI compressor filter in the collection $css->addFilter( new CssYUICompressor( [ 'java-bin' => '/usr/local/bin/java', 'yui' => '/some/path/yuicompressor-x.y.z.jar', 'extra-options' => '--charset utf8', ] ) ); ``` 在前面的示例中,我们使用了名为`LicenseStamper`的自定义过滤器: ```php <?php use Phalcon\Assets\FilterInterface; /** * Adds a license message to the top of the file * * @param string $contents * * @return string */ class LicenseStamper implements FilterInterface { /** * Do the filtering * * @param string $contents * @return string */ public function filter($contents) { $license = '/* (c) 2015 Your Name Here */'; return $license . PHP_EOL . PHP_EOL . $contents; } } ``` ## 自定义输出 `outputJs()` 和 `outputCss()`方法可用于根据每种类型的资源生成必要的HTML代码。您可以通过以下方式覆盖此方法或手动打印资源: ```php <?php use Phalcon\Tag; $jsCollection = $this->assets->collection('js'); foreach ($jsCollection as $resource) { echo Tag::javascriptInclude( $resource->getPath() ); } ``` ## 提高性能 有许多方法可以优化处理资源。我们将在下面描述一种简单的方法,允许直接通过Web服务器处理资源以优化响应时间。 首先,我们需要设置 Assets管理器。我们将使用基本控制器,但您可以使用服务提供商或任何其他地方: ```php <?php namespace App\Controllers; use Phalcon\Mvc\Controller; use Phalcon\Assets\Filters\Jsmin; /** * App\Controllers\ControllerBase * * This is the base controller for all controllers in the application. */ class ControllerBase extends Controller { public function onConstruct() { $this->assets ->useImplicitOutput(false) ->collection('global') ->addJs('https://code.jquery.com/jquery-3.2.1.js', false, true) ->addFilter(new Jsmin()); } } ``` 然后我们必须配置路由: ```php <?php /* * Define custom routes. * This file gets included in the router service definition. */ $router = new Phalcon\Mvc\Router(); $router->addGet('/assets/(css|js)/([\w.-]+)\.(css|js)', [ 'controller' => 'assets', 'action' => 'serve', 'type' => 1, 'collection' => 2, 'extension' => 3, ]); // Other routes... ``` 最后,我们需要创建一个控制器来处理资源请求: ```php <?php namespace App\Controllers; use Phalcon\Http\Response; /** * Serve site assets. */ class AssetsController extends ControllerBase { public function serveAction() : Response { // Getting a response instance $response = new Response(); // Prepare output path $collectionName = $this->dispatcher->getParam('collection'); $extension = $this->dispatcher->getParam('extension'); $type = $this->dispatcher->getParam('type'); $targetPath = "assets/{$type}/{$collectionName}.{$extension}"; // Setting up the content type $contentType = $type == 'js' ? 'application/javascript' : 'text/css'; $response->setContentType($contentType, 'UTF-8'); // Check collection existence if (!$this->assets->exists($collectionName)) { return $response->setStatusCode(404, 'Not Found'); } // Setting up the Assets Collection $collection = $this->assets ->collection($collectionName) ->setTargetUri($targetPath) ->setTargetPath($targetPath); // Store content to the disk and return fully qualified file path $contentPath = $this->assets->output($collection, function (array $parameters) { return BASE_PATH . '/public/' . $parameters[0]; }, $type); // Set the content of the response $response->setContent(file_get_contents($contentPath)); // Return the response return $response; } } ``` 如果文件系统中存在预编译资源,则必须由Web服务器直接提供。因此,要获得静态资源的好处,我们必须更新服务器配置。我们将使用Nginx的示例配置。对于Apache来说,它会有所不同: ```nginx location ~ ^/assets/ { expires 1y; add_header Cache-Control public; add_header ETag ""; # If the file exists as a static file serve it directly without # running all the other rewrite tests on it try_files $uri $uri/ @phalcon; } location / { try_files $uri $uri/ @phalcon; } location @phalcon { rewrite ^(.*)$ /index.php?_url=$1; } # Other configuration ``` 我们需要在应用程序的文档根目录中创建`assets/js`和`assets/css`目录(例如`public`)。 每当用户使用`/assets/js/global.js`类型的地址请求资源时,如果文件系统中没有此文件,请求将被重定向到 `AssetsController` 。否则,资源将由Web服务器处理。 这不是最好的例子。但是,它反映了主要思想:使用应用程序合理配置Web服务器可以帮助优化多倍的响应时间。 在专用文章Web服务器设置和路由中了解有关Web服务器设置和路由的详细信息。