<article><h1>Laravel 的 HTTP 控制器</h1><ul><li><a href="#introduction">简介</a></li><li><a href="#basic-controllers">基础控制器</a><ul><li><a href="#defining-controllers">定义控制器</a></li><li><a href="#controllers-and-namespaces">控制器与命名空间</a></li><li><a href="#single-action-controllers">单一操作控制器</a></li></ul></li><li><a href="#controller-middleware">控制器中间件</a></li><li><a href="#resource-controllers">资源控制器</a><ul><li><a href="#restful-partial-resource-routes">部分资源路由</a></li><li><a href="#restful-naming-resource-routes">命名资源路由</a></li><li><a href="#restful-naming-resource-route-parameters">命名资源路由参数</a></li><li><a href="#restful-localizing-resource-uris">本地化资源 URI</a></li><li><a href="#restful-supplementing-resource-controllers">附加资源控制器</a></li></ul></li><li><a href="#dependency-injection-and-controllers">依赖注入与控制器</a></li><li><a href="#route-caching">路由缓存</a></li></ul><p><a name="introduction"></a></p><h2><a href="#introduction">简介</a></h2><p>除了在路由文件中以闭包的形式定义所有的请求处理逻辑外,你可能还想使用控制器类来组织此类操作。控制器能够将相关的请求处理逻辑组成一个单独的类。控制器被存放在 <code class=" language-php">app<span class="token operator">/</span>Http<span class="token operator">/</span>Controllers</code> 目录下。</p><p><a name="basic-controllers"></a></p><h2><a href="#basic-controllers">基础控制器</a></h2><p><a name="defining-controllers"></a></p><h3>定义控制器</h3><p>以下是一个基础控制器类的例子。需要注意的是,该控制器继承了 Laravel 内置的基础控制器类。该基础类提供了一些便捷的方法,比如 <code class=" language-php">middleware</code> 方法,该方法可以用来给控制器操作添加中间件:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">UserController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 展示给定用户的信息。
*
* @param int $id
* @return Response
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">show<span class="token punctuation">(</span></span><span class="token variable">$id</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">view<span class="token punctuation">(</span></span><span class="token string">'user.profile'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'user'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token scope">User<span class="token punctuation">::</span></span><span class="token function">findOrFail<span class="token punctuation">(</span></span><span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p>你可以这样定义一个指向该控制器操作的路由:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get<span class="token punctuation">(</span></span><span class="token string">'user/{id}'</span><span class="token punctuation">,</span> <span class="token string">'UserController@show'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>现在,当请求和此特定路由的 URI 匹配时,<code class=" language-php">UserController</code> 类的 <code class=" language-php">show</code> 方法就会被执行。当然,路由参数也会被传递至该方法。</p><blockquote class="has-icon tip"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="56.6px" height="87.5px" viewBox="0 0 56.6 87.5" enable-background="new 0 0 56.6 87.5" xml:space="preserve"><path fill="#FFFFFF" d="M28.7 64.5c-1.4 0-2.5-1.1-2.5-2.5v-5.7 -5V41c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5v10.1 5 5.8C31.2 63.4 30.1 64.5 28.7 64.5zM26.4 0.1C11.9 1 0.3 13.1 0 27.7c-0.1 7.9 3 15.2 8.2 20.4 0.5 0.5 0.8 1 1 1.7l3.1 13.1c0.3 1.1 1.3 1.9 2.4 1.9 0.3 0 0.7-0.1 1.1-0.2 1.1-0.5 1.6-1.8 1.4-3l-2-8.4 -0.4-1.8c-0.7-2.9-2-5.7-4-8 -1-1.2-2-2.5-2.7-3.9C5.8 35.3 4.7 30.3 5.4 25 6.7 14.5 15.2 6.3 25.6 5.1c13.9-1.5 25.8 9.4 25.8 23 0 4.1-1.1 7.9-2.9 11.2 -0.8 1.4-1.7 2.7-2.7 3.9 -2 2.3-3.3 5-4 8L41.4 53l-2 8.4c-0.3 1.2 0.3 2.5 1.4 3 0.3 0.2 0.7 0.2 1.1 0.2 1.1 0 2.2-0.8 2.4-1.9l3.1-13.1c0.2-0.6 0.5-1.2 1-1.7 5-5.1 8.2-12.1 8.2-19.8C56.4 12 42.8-1 26.4 0.1zM43.7 69.6c0 0.5-0.1 0.9-0.3 1.3 -0.4 0.8-0.7 1.6-0.9 2.5 -0.7 3-2 8.6-2 8.6 -1.3 3.2-4.4 5.5-7.9 5.5h-4.1H28h-0.5 -3.6c-3.5 0-6.7-2.4-7.9-5.7l-0.1-0.4 -1.8-7.8c-0.4-1.1-0.8-2.1-1.2-3.1 -0.1-0.3-0.2-0.5-0.2-0.9 0.1-1.3 1.3-2.1 2.6-2.1H41C42.4 67.5 43.6 68.2 43.7 69.6zM37.7 72.5H26.9c-4.2 0-7.2 3.9-6.3 7.9 0.6 1.3 1.8 2.1 3.2 2.1h4.1 0.5 0.5 3.6c1.4 0 2.7-0.8 3.2-2.1L37.7 72.5z"></path></svg></span></div> 控制器并不是 <strong>一定</strong> 要继承基础类。只是,你将无法使用一些便捷的功能,比如 <code class=" language-php">middleware</code>,<code class=" language-php">validate</code> 和 <code class=" language-php">dispatch</code> 方法。</p></blockquote><p><a name="controllers-and-namespaces"></a></p><h3>控制器与命名空间</h3><p>这一点很重要,我们在定义控制器路由时,不必指定完整的控制器命名空间。<code class=" language-php">RouteServiceProvider</code> 会在一个包含命名空间的路由组中加载路由文件,因此我们只需要指定类名中 <code class=" language-php">App\<span class="token package">Http<span class="token punctuation">\</span>Controllers</span></code> 命名空间之后的部分就可以了。</p><p>如果你选择将控制器存放在 <code class=" language-php">App\<span class="token package">Http<span class="token punctuation">\</span>Controllers</span></code> 目录下,只需简单地使用相对于根命名空间 <code class=" language-php">App\<span class="token package">Http<span class="token punctuation">\</span>Controllers</span></code> 的特定类名。因此,如果你的完整控制器类是 <code class=" language-php">App\<span class="token package">Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Photos<span class="token punctuation">\</span>AdminController</span></code>,你应该用这种方式注册指向该控制器的路由:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get<span class="token punctuation">(</span></span><span class="token string">'foo'</span><span class="token punctuation">,</span> <span class="token string">'Photos\AdminController@method'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p><a name="single-action-controllers"></a></p><h3>单一操作控制器</h3><p>如果想定义一个只处理单个操作的控制器,你可以在控制器中只设置一个 <code class=" language-php">__invoke</code> 方法:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">ShowProfile</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 展示给定用户的信息。
*
* @param int $id
* @return Response
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__invoke<span class="token punctuation">(</span></span><span class="token variable">$id</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">view<span class="token punctuation">(</span></span><span class="token string">'user.profile'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'user'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token scope">User<span class="token punctuation">::</span></span><span class="token function">findOrFail<span class="token punctuation">(</span></span><span class="token variable">$id</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p>为单一操作控制器注册路由时,无需指定方法:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get<span class="token punctuation">(</span></span><span class="token string">'user/{id}'</span><span class="token punctuation">,</span> <span class="token string">'ShowProfile'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p><a name="controller-middleware"></a></p><h2><a href="#controller-middleware">控制器中间件</a></h2><p><a href="/docs/5.4/middleware">中间件</a> 可以在路由文件中指定给控制器路由:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get<span class="token punctuation">(</span></span><span class="token string">'profile'</span><span class="token punctuation">,</span> <span class="token string">'UserController@show'</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token string">'auth'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>然而,在控制器的构造方法中指定中间件会更为便捷。在控制器构造方法中使用 <code class=" language-php">middleware</code> 方法,你可以很容易地将中间件指定给控制器操作。你甚至可以约束中间件只对控制器类中的某个特定方法生效:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">class</span> <span class="token class-name">UserController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 创建一个新的控制器实例。
*
* @return void
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token string">'auth'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token string">'log'</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">only<span class="token punctuation">(</span></span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token string">'subscribed'</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">except<span class="token punctuation">(</span></span><span class="token string">'store'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p>控制器也允许你使用闭包的方式注册中间件。这提供了一种很便捷地为单个控制器定义中间件的方式,而不用定义一个完整的中间件类:</p><pre class=" language-php"><code class=" language-php"><span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">middleware<span class="token punctuation">(</span></span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$next</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> // ...
</span>
<span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><blockquote class="has-icon tip"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="56.6px" height="87.5px" viewBox="0 0 56.6 87.5" enable-background="new 0 0 56.6 87.5" xml:space="preserve"><path fill="#FFFFFF" d="M28.7 64.5c-1.4 0-2.5-1.1-2.5-2.5v-5.7 -5V41c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5v10.1 5 5.8C31.2 63.4 30.1 64.5 28.7 64.5zM26.4 0.1C11.9 1 0.3 13.1 0 27.7c-0.1 7.9 3 15.2 8.2 20.4 0.5 0.5 0.8 1 1 1.7l3.1 13.1c0.3 1.1 1.3 1.9 2.4 1.9 0.3 0 0.7-0.1 1.1-0.2 1.1-0.5 1.6-1.8 1.4-3l-2-8.4 -0.4-1.8c-0.7-2.9-2-5.7-4-8 -1-1.2-2-2.5-2.7-3.9C5.8 35.3 4.7 30.3 5.4 25 6.7 14.5 15.2 6.3 25.6 5.1c13.9-1.5 25.8 9.4 25.8 23 0 4.1-1.1 7.9-2.9 11.2 -0.8 1.4-1.7 2.7-2.7 3.9 -2 2.3-3.3 5-4 8L41.4 53l-2 8.4c-0.3 1.2 0.3 2.5 1.4 3 0.3 0.2 0.7 0.2 1.1 0.2 1.1 0 2.2-0.8 2.4-1.9l3.1-13.1c0.2-0.6 0.5-1.2 1-1.7 5-5.1 8.2-12.1 8.2-19.8C56.4 12 42.8-1 26.4 0.1zM43.7 69.6c0 0.5-0.1 0.9-0.3 1.3 -0.4 0.8-0.7 1.6-0.9 2.5 -0.7 3-2 8.6-2 8.6 -1.3 3.2-4.4 5.5-7.9 5.5h-4.1H28h-0.5 -3.6c-3.5 0-6.7-2.4-7.9-5.7l-0.1-0.4 -1.8-7.8c-0.4-1.1-0.8-2.1-1.2-3.1 -0.1-0.3-0.2-0.5-0.2-0.9 0.1-1.3 1.3-2.1 2.6-2.1H41C42.4 67.5 43.6 68.2 43.7 69.6zM37.7 72.5H26.9c-4.2 0-7.2 3.9-6.3 7.9 0.6 1.3 1.8 2.1 3.2 2.1h4.1 0.5 0.5 3.6c1.4 0 2.7-0.8 3.2-2.1L37.7 72.5z"></path></svg></span></div> 你可能将中间件指定到控制器的部分操作上,然而,这会使你的控制器过于臃肿。换个角度,考虑将控制器分成多个更小的控制器。</p></blockquote><p><a name="resource-controllers"></a></p><h2><a href="#resource-controllers">资源控制器</a></h2><p>Laravel 资源路由可以将典型的「CURD」路由指定到一个控制器上,仅需一行代码就可以实现。比如,你可能希望创建一个控制器来处理所有应用保存的「相片」的 HTTP 请求。使用 Artisan 命令 <code class=" language-php">make<span class="token punctuation">:</span>controller</code>,就能快速创建这样一个控制器:</p><pre class=" language-php"><code class=" language-php">php artisan make<span class="token punctuation">:</span>controller PhotoController <span class="token operator">--</span>resource</code></pre><p>这个命令会在 <code class=" language-php">app<span class="token operator">/</span>Http<span class="token operator">/</span>Controllers<span class="token operator">/</span>PhotoController<span class="token punctuation">.</span>php</code> 中生成一个控制器,该控制器包含了各种可用的资源操作方法。</p><p>接下来,你可以给控制器注册一个资源路由:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">resource<span class="token punctuation">(</span></span><span class="token string">'photos'</span><span class="token punctuation">,</span> <span class="token string">'PhotoController'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>这个路由声明会创建多个路由来处理各种各样的资源操作。前面生成的控制器已经包含了这些操作的方法,还包括了 HTTP 动作和操作 URI 的注释。</p><h4>资源控制器操作处理</h4><table><thead><tr><th>动作</th><th>URI</th><th>操作</th><th>路由名称</th></tr></thead><tbody><tr><td>GET</td><td><code class=" language-php"><span class="token operator">/</span>photos</code></td><td>index</td><td>photos.index</td></tr><tr><td>GET</td><td><code class=" language-php"><span class="token operator">/</span>photos<span class="token operator">/</span>create</code></td><td>create</td><td>photos.create</td></tr><tr><td>POST</td><td><code class=" language-php"><span class="token operator">/</span>photos</code></td><td>store</td><td>photos.store</td></tr><tr><td>GET</td><td><code class=" language-php"><span class="token operator">/</span>photos<span class="token operator">/</span><span class="token punctuation">{</span>photo<span class="token punctuation">}</span></code></td><td>show</td><td>photos.show</td></tr><tr><td>GET</td><td><code class=" language-php"><span class="token operator">/</span>photos<span class="token operator">/</span><span class="token punctuation">{</span>photo<span class="token punctuation">}</span><span class="token operator">/</span>edit</code></td><td>edit</td><td>photos.edit</td></tr><tr><td>PUT/PATCH</td><td><code class=" language-php"><span class="token operator">/</span>photos<span class="token operator">/</span><span class="token punctuation">{</span>photo<span class="token punctuation">}</span></code></td><td>update</td><td>photos.update</td></tr><tr><td>DELETE</td><td><code class=" language-php"><span class="token operator">/</span>photos<span class="token operator">/</span><span class="token punctuation">{</span>photo<span class="token punctuation">}</span></code></td><td>destroy</td><td>photos.destroy</td></tr></tbody></table><h4>指定资源模型</h4><p>如果你使用了路由模型绑定,并且想在资源控制器的方法中对某个模型实例做类型约束,你可以在生成控制器的时候使用 <code class=" language-php"><span class="token operator">--</span>model</code> 选项:</p><pre class=" language-php"><code class=" language-php">php artisan make<span class="token punctuation">:</span>controller PhotoController <span class="token operator">--</span>resource <span class="token operator">--</span>model<span class="token operator">=</span>Photo</code></pre><h4>伪造表单方法</h4><p>送 <code class=" language-php"><span class="token constant">PUT</span></code>,<code class=" language-php"><span class="token constant">PATCH</span></code> 或者 <code class=" language-php"><span class="token constant">DELETE</span></code> 请求,你需要添加一个 <code class=" language-php">_method</code> 隐藏域字段来伪造 HTTP 动作。<code class=" language-php">method_field</code> 辅助函数可以为你创建这个字段:</p><pre class=" language-php"><code class=" language-php"><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">method_field<span class="token punctuation">(</span></span><span class="token string">'PUT'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p><a name="restful-partial-resource-routes"></a></p><h3>部分资源路由</h3><p>声明资源路由的时候,你可以指定控制器处理部分操作,而不必使用全部默认的操作:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">resource<span class="token punctuation">(</span></span><span class="token string">'photo'</span><span class="token punctuation">,</span> <span class="token string">'PhotoController'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'only'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'index'</span><span class="token punctuation">,</span> <span class="token string">'show'</span>
<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">resource<span class="token punctuation">(</span></span><span class="token string">'photo'</span><span class="token punctuation">,</span> <span class="token string">'PhotoController'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'except'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'create'</span><span class="token punctuation">,</span> <span class="token string">'store'</span><span class="token punctuation">,</span> <span class="token string">'update'</span><span class="token punctuation">,</span> <span class="token string">'destroy'</span>
<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p><a name="restful-naming-resource-routes"></a></p><h3>命名资源路由</h3><p>默认地,所有的资源路由操作都有一个路由名称;不过你可以在参数选项中传入一个 <code class=" language-php">names</code> 数组来重写这些名称:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">resource<span class="token punctuation">(</span></span><span class="token string">'photo'</span><span class="token punctuation">,</span> <span class="token string">'PhotoController'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'names'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'create'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token string">'photo.build'</span>
<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p><a name="restful-naming-resource-route-parameters"></a></p><h3>命名资源路由参数</h3><p>默认地,<code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span>resource</code> 会基于资源名称的「单数」形式生成路由参数。你可以在选项数组中传入 <code class=" language-php">parameters</code> 参数,实现每个资源基础中参数名称的重写。<code class=" language-php">parameters</code> 应该是一个将资源名称和参数名称联系在一起的数组:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">resource<span class="token punctuation">(</span></span><span class="token string">'user'</span><span class="token punctuation">,</span> <span class="token string">'AdminUserController'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'parameters'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>
<span class="token string">'user'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token string">'admin_user'</span>
<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>上例将会为 <code class=" language-php">show</code> 方法的路由生成如下的 URI:</p><pre class=" language-php"><code class=" language-php"><span class="token operator">/</span>user<span class="token operator">/</span><span class="token punctuation">{</span>admin_user<span class="token punctuation">}</span></code></pre><p><a name="restful-localizing-resource-uris"></a></p><h3>本地化资源 URI</h3><p>默认地,<code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span>resource</code> 将会用英文动词创建资源 URI。如果你想本地化 <code class=" language-php">create</code> 和 <code class=" language-php">edit</code> 的动作名,可以使用 <code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span>resourceVerb</code> 方法,可以在 <code class=" language-php">AppServiceProvider</code> 的 <code class=" language-php">boot</code> 方法中实现:</p><pre class=" language-php"><code class=" language-php"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Route</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">/**
* 自定义任何应用服务。
*
* @return void
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">boot<span class="token punctuation">(</span></span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">resourceVerbs<span class="token punctuation">(</span></span><span class="token punctuation">[</span>
<span class="token string">'create'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token string">'crear'</span><span class="token punctuation">,</span>
<span class="token string">'edit'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token string">'editar'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre><p>动作名被自定义后,像 <code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">resource<span class="token punctuation">(</span></span><span class="token string">'fotos'</span><span class="token punctuation">,</span> <span class="token string">'PhtotController'</span><span class="token punctuation">)</span></code> 这样注册的资源路由将会产生如下的 URI:</p><pre class=" language-php"><code class=" language-php"><span class="token operator">/</span>fotos<span class="token operator">/</span>crear
<span class="token operator">/</span>fotos<span class="token operator">/</span><span class="token punctuation">{</span>foto<span class="token punctuation">}</span><span class="token operator">/</span>editar</code></pre><p><a name="restful-supplementing-resource-controllers"></a></p><h3>附加资源控制器</h3><p>如果你想在默认的资源路由之外增加资源控制器路由,你应该在调用 <code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span>resource</code> 之前定义这些路由;否则,<code class=" language-php">resource</code> 方法定义的路由可能会不小心覆盖你的附加路由:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get<span class="token punctuation">(</span></span><span class="token string">'photos/popular'</span><span class="token punctuation">,</span> <span class="token string">'PhotoController@method'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">resource<span class="token punctuation">(</span></span><span class="token string">'photos'</span><span class="token punctuation">,</span> <span class="token string">'PhotoController'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><blockquote class="has-icon tip"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="56.6px" height="87.5px" viewBox="0 0 56.6 87.5" enable-background="new 0 0 56.6 87.5" xml:space="preserve"><path fill="#FFFFFF" d="M28.7 64.5c-1.4 0-2.5-1.1-2.5-2.5v-5.7 -5V41c0-1.4 1.1-2.5 2.5-2.5s2.5 1.1 2.5 2.5v10.1 5 5.8C31.2 63.4 30.1 64.5 28.7 64.5zM26.4 0.1C11.9 1 0.3 13.1 0 27.7c-0.1 7.9 3 15.2 8.2 20.4 0.5 0.5 0.8 1 1 1.7l3.1 13.1c0.3 1.1 1.3 1.9 2.4 1.9 0.3 0 0.7-0.1 1.1-0.2 1.1-0.5 1.6-1.8 1.4-3l-2-8.4 -0.4-1.8c-0.7-2.9-2-5.7-4-8 -1-1.2-2-2.5-2.7-3.9C5.8 35.3 4.7 30.3 5.4 25 6.7 14.5 15.2 6.3 25.6 5.1c13.9-1.5 25.8 9.4 25.8 23 0 4.1-1.1 7.9-2.9 11.2 -0.8 1.4-1.7 2.7-2.7 3.9 -2 2.3-3.3 5-4 8L41.4 53l-2 8.4c-0.3 1.2 0.3 2.5 1.4 3 0.3 0.2 0.7 0.2 1.1 0.2 1.1 0 2.2-0.8 2.4-1.9l3.1-13.1c0.2-0.6 0.5-1.2 1-1.7 5-5.1 8.2-12.1 8.2-19.8C56.4 12 42.8-1 26.4 0.1zM43.7 69.6c0 0.5-0.1 0.9-0.3 1.3 -0.4 0.8-0.7 1.6-0.9 2.5 -0.7 3-2 8.6-2 8.6 -1.3 3.2-4.4 5.5-7.9 5.5h-4.1H28h-0.5 -3.6c-3.5 0-6.7-2.4-7.9-5.7l-0.1-0.4 -1.8-7.8c-0.4-1.1-0.8-2.1-1.2-3.1 -0.1-0.3-0.2-0.5-0.2-0.9 0.1-1.3 1.3-2.1 2.6-2.1H41C42.4 67.5 43.6 68.2 43.7 69.6zM37.7 72.5H26.9c-4.2 0-7.2 3.9-6.3 7.9 0.6 1.3 1.8 2.1 3.2 2.1h4.1 0.5 0.5 3.6c1.4 0 2.7-0.8 3.2-2.1L37.7 72.5z"></path></svg></span></div> 记住保持控制器的专一性。如果你需要典型的资源操作之外的方法,考虑将你的控制器分成两个更小的控制器吧。</p></blockquote><p><a name="dependency-injection-and-controllers"></a></p><h2><a href="#dependency-injection-and-controllers">依赖注入与控制器</a></h2><h4>构造方法注入</h4><p>Laravel 使用 <a href="/docs/5.4/container">服务容器</a> 来解析所有的控制器。因此,你可以在控制器的构造方法中对任何依赖使用类型约束,声明的依赖会自动被解析并注入控制器实例中:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Repositories<span class="token punctuation">\</span>UserRepository</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">UserController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 用户 repository 实例。
*/</span>
<span class="token keyword">protected</span> <span class="token variable">$users</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">/**
* 创建一个新的控制器实例。
*
* @param UserRepository $users
* @return void
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct<span class="token punctuation">(</span></span>UserRepository <span class="token variable">$users</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token this">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">users</span> <span class="token operator">=</span> <span class="token variable">$users</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p>当然,你也可以对任何的 <a href="/docs/5.4/contracts">Laravel contract</a> 使用类型约束。当容器解析 contract 的时候,就会使用类型约束。直接将依赖注入控制器可能会提供更好的可测试性,但这取决于你的项目的具体情况。</p><h4>方法注入</h4><p>除了构造方法注入之外,你还可以在控制器方法中使用依赖类型约束。一个常见的用法就是将 <code class=" language-php">Illuminate\<span class="token package">Http<span class="token punctuation">\</span>Request</span></code> 实例注入控制器方法中:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">UserController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 保存一个新用户。
*
* @param Request $request
* @return Response
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">store<span class="token punctuation">(</span></span>Request <span class="token variable">$request</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token variable">$name</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">name</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true"> //
</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p>如果控制器方法需要从路由参数中获取输入内容,只需在其他依赖后列出路由参数即可。比如,路由定义如下:</p><pre class=" language-php"><code class=" language-php"><span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">put<span class="token punctuation">(</span></span><span class="token string">'user/{id}'</span><span class="token punctuation">,</span> <span class="token string">'UserController@update'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>通过以下方式定义控制器方法,可以让你在使用 <code class=" language-php">Illuminate\<span class="token package">Http<span class="token punctuation">\</span>Request</span></code> 类型约束的同时仍然可以获取参数 <code class=" language-php">id</code>:</p><pre class=" language-php"><code class=" language-php"><span class="token delimiter"><?php</span>
<span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name">UserController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true">/**
* 更新给定用户的信息。
*
* @param Request $request
* @param string $id
* @return Response
*/</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">update<span class="token punctuation">(</span></span>Request <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token variable">$id</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment" spellcheck="true"> //
</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre><p><a name="route-caching"></a></p><h2><a href="#route-caching">路由缓存</a></h2><blockquote class="has-icon note"><p><div class="flag"><span class="svg"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" version="1.1" x="0px" y="0px" width="90px" height="90px" viewBox="0 0 90 90" enable-background="new 0 0 90 90" xml:space="preserve"><path fill="#FFFFFF" d="M45 0C20.1 0 0 20.1 0 45s20.1 45 45 45 45-20.1 45-45S69.9 0 45 0zM45 74.5c-3.6 0-6.5-2.9-6.5-6.5s2.9-6.5 6.5-6.5 6.5 2.9 6.5 6.5S48.6 74.5 45 74.5zM52.1 23.9l-2.5 29.6c0 2.5-2.1 4.6-4.6 4.6 -2.5 0-4.6-2.1-4.6-4.6l-2.5-29.6c-0.1-0.4-0.1-0.7-0.1-1.1 0-4 3.2-7.2 7.2-7.2 4 0 7.2 3.2 7.2 7.2C52.2 23.1 52.2 23.5 52.1 23.9z"></path></svg></span></div> 基于闭包的路由并不能被缓存。如果要使用路由缓存,你必须将所有的闭包路由转换成控制器类。</p></blockquote><p>如果你的应用只用到了基于控制器的路由,那么你应该充分利用 Laravel 的路由缓存。使用路由缓存将极大地减少注册全部应用路由的时间。某些情况下,路由注册甚至可以快一百倍。要生成路由缓存,只需在 Artisan 命令行中执行 <code class=" language-php">route<span class="token punctuation">:</span>cache</code> 命令:</p><pre class=" language-php"><code class=" language-php">php artisan route<span class="token punctuation">:</span>cache</code></pre><p>运行这个命令之后,每一次请求的时候都将会加载缓存的路由文件。记住,如果添加了新的路由,你需要刷新路由缓存。因此,你应该只在项目部署时才运行 <code class=" language-php">route<span class="token punctuation">:</span>cache</code> 命令:</p><p>你可以使用 <code class=" language-php">route<span class="token punctuation">:</span>clear</code> 命令清除路由缓存:</p><pre class=" language-php"><code class=" language-php">php artisan route<span class="token punctuation">:</span>clear</code></pre><h2>译者署名</h2><table><thead><tr><th>用户名</th><th>头像</th><th>职能</th><th>签名</th></tr></thead><tbody><tr><td><a href="https://github.com/Romeo0906">@Romeo</a></td><td><img class="avatar-66 rm-style" src="https://avatars1.githubusercontent.com/u/22153498?v=3&s=460"></td><td>翻译</td><td>No bug, no gain.</td></tr></tbody></table></article>
- 入门指南
- 安装
- 配置信息
- 文件夹结构
- 请求周期
- 开发环境部署
- Valet
- Homestead
- 核心概念
- 服务提供者
- Facades
- Contracts
- 服务容器
- HTTP 层
- 路由
- 中间件
- CSRF 保护
- 控制器
- 请求
- 响应
- 视图
- Session
- 表单验证
- 前端
- Blade 模板
- 本地化
- 前端指南
- 编辑资源 Mix
- 安全
- API 认证
- 用户认证
- 用户授权
- 加密解密
- 哈希
- 重置密码
- 数据库
- 快速入门
- 查询构造器
- 分页
- 数据库迁移
- Redis
- 数据填充
- Eloquent ORM
- Eloquent ORM快速入门
- 模型关联
- Eloquent 集合
- 修改器
- 序列化
- 综合话题
- Artisan 命令行
- 广播系统
- 缓存系统
- 集合
- 错误与日志
- 事件系统
- 文件存储
- 辅助函数
- 邮件发送
- 消息通知
- 扩展包开发
- 队列
- 任务调度