五、为网址和应用接口使用控制器和路由

在本章中,我们将介绍:

  • 创建基本控制器
  • 使用闭合创建路线
  • 创建 RESTful 控制器
  • 使用高级路由
  • 在路线上使用过滤器
  • 使用路由组
  • 构建一个带有路由的 RESTful 应用编程接口
  • 使用命名路由
  • 在路线中使用子域

简介

在本章中,我们将介绍一些使用 Laravel 路由系统的方法。有两种基本方法来路由我们的应用:要么用闭包在routes.php文件中设置路由,要么使用控制器。我们将看到这些方法的威力,并展示它们如何在我们的应用中使用。

创建基本控制器

模型-视图-控制器 ( MVC )模式在 PHP 框架中非常流行。在本食谱中,我们将创建一个简单的控制器,扩展另一个基本控制器。

做好准备

首先,我们只需要一个标准的 Laravel 安装。

怎么做...

要完成此配方,请遵循以下步骤:

  1. app/controllers目录中,创建一个名为UsersController.php的文件,并在其中键入以下代码:

    ```php <?php class UsersController extends BaseController {

    public function actionIndex() { return "This is a User Index page"; }

    public function actionAbout() { return "This is a User About page"; } } ```

  2. 然后,在routes.php文件中,添加以下行:

    php Route::get('users', 'UsersController@actionIndex'); Route::get('users/about', 'UsersController@actionAbout');

  3. 通过进入http://your-server/usershttp://your-server/users/about测试控制器,其中your-server是你的应用的网址。

它是如何工作的...

在我们的用户控制器(以及我们创建的几乎所有其他控制器)中,我们从扩展基本控制器开始。如果我们查看 BaseController.php文件,我们只看到一个方法, setupLayout()方法,它用于我们的布局视图。如果我们想在网站的每个页面上运行一些代码,也可以使用基本控制器。

回到用户控制器,我们为我们的索引和关于页面定义了两种方法,每种方法都以action为前缀。出于我们的目的,我们只返回一个字符串,但这将是我们所有控制器逻辑的去向,也是我们设置显示视图的地方。

为了让 Laravel 能够解析 URL 并确定使用哪个控制器和方法,我们需要在我们的routes文件中注册路由。现在,在我们的浏览器中,当我们进入/users(或/users/index)时,我们将被带到我们的索引页面,而/users/about将带我们进入我们的关于页面。

使用闭合创建路线

如果我们决定不使用 MVC 模式,我们可以通过使用闭包或者匿名函数来创建我们的路由。

做好准备

对于这个配方,我们只需要一个标准的 Laravel 安装。

怎么做...

要完成此配方,请遵循以下步骤:

  1. app/routes.php文件中,添加如下路线:

    php Route::get('hello/world', function() { $hello = 'Hello '; $world = 'World!'; return $hello . $world; });

  2. 打开浏览器,通过访问http://your-server/hello/world测试路线,其中your-server是你的应用的网址。

它是如何工作的...

Laravel 中的路由被认为是 RESTful,这意味着它们响应各种不同的 HTTP 动词。大多数时候,当简单地浏览网页时,我们使用GET动词,就像在Route::get中一样。我们的第一个参数是我们用于路由的网址,它几乎可以是任何有效的网址字符串。在我们的例子中,当一个用户去hello/world时,它会使用这条路线。之后就是我们的闭包,或者说匿名函数。

在闭包中,我们可以从模型中提取任何数据,做任何我们想做的逻辑,并调用我们想使用的视图。在我们的示例中,我们只是设置了几个变量并返回它们的串联值。

创建 RESTful 控制器

可能有一段时间,我们希望拥有一个 RESTful web 应用,比如在构建一个 API 的时候。为了实现这一点,我们需要我们的路由来响应各种 HTTP 请求。带有闭包的路由已经以这种方式设置好了,但是在这个食谱中,我们将停留在 MVC 模式中,并创建一个名为 RESTful 的控制器。

做好准备

对于这个配方,我们需要一个标准的 Laravel 安装和来自创建基本控制器配方的代码。

怎么做...

要完成此配方,请遵循以下步骤:

  1. 在用户控制器中,用以下代码替换该代码:

    ```php <?php class UsersController extends BaseController {

    public function getIndex() { $my_form = "

    "; return $my_form;

    } public function postIndex() { dd(Input::all()); }

    public function getAbout() { return "This is a User About page"; } } ```

  2. routes.php中,将路线添加到我们的控制器:

    php Route::controller('users', 'UsersController');

  3. 在浏览器中,转到http://your-server/users(其中your-server是您的网络服务器的网址)并点击提交按钮。

  4. 在浏览器中,转到http://your-server/users/about

它是如何工作的...

RESTful 和非 RESTful 控制器之间的两个主要区别是将方法重命名为它们响应的 HTTP 请求作为前缀,并使用Route::controller()注册我们的路由。

我们的getIndex()方法是我们去/users时的默认方法,因为大部分页面浏览量都是GET请求。在这个例子中,我们返回了一个非常简单的表单,它将把输入返回给它自己。但是,由于表单使用的是POST请求,它将触发 postIndex()方法,这就是表单可以被处理的地方。在我们的例子中,我们只是使用 Laravel 的dd()助手来显示提交的表单输入。

使用高级路由

创建需要参数的路线时,我们可能需要使用更高级的功能。使用 Laravel 和正则表达式,我们可以确保我们的路由只响应特定的 URL。

做好准备

对于这个食谱,我们需要一个标准的 Laravel 安装。

怎么做…

要完成此配方,请遵循以下步骤:

  1. 在我们的routes.php文件中,添加以下代码:

    ```php Route::get('tvshow/{show?}/{year?}', function($show = null, $year = null) { if (!$show && !$year) { return 'You did not pick a show.'; } elseif (!$year) { return 'You picked the show ' . $show . ''; }

    return 'You picked the show ' . $show .' from the year ' . $year . '.'; }) ->where('year', '\d{4}'); ```

  2. 打开浏览器,通过在地址栏中键入诸如http://your-server/tvshow/MASH/1981(其中your-server是您的服务器的网址)等内容来测试路线。

它是如何工作的...

我们从开始,让我们的路线响应tvshow的请求。如果我们想将参数传递给路由,我们需要设置通配符。只要我们将相同的名称传递给函数,我们就可以使用任意多的参数,并为它们命名。对于这个食谱,我们想得到一个显示标题,为了使这个参数可选,我们在最后添加了问号。

对于我们的第二个参数,我们想要一个year。在这种情况下,它必须是一个四位数。为了使用正则表达式,我们用参数和表达式的名称将where()方法链接到我们的路线。在这个例子中,我们只需要数字(\d),并且必须有四个数字({4})。路线参数中的问号使该字段成为可选字段。

在我们的闭包中,我们使用我们设置的相同名称为每个通配符设置变量。为了使它们可选,我们将每个变量默认设置为null。然后我们检查参数是否设置好了,如果设置好了,就返回一个适当的消息。

在路线上使用过滤器

Laravel 的一个强大功能是添加过滤器,可以在向我们的应用发出请求之前和之后运行。在这个食谱中,我们将探索这些过滤器。

做好准备

对于这个食谱,我们只需要一个标准的 Laravel 安装。

怎么做...

要完成此配方,请遵循以下步骤:

  1. 在我们的routes.php文件中,添加一个只有管理员才能访问的路由,并附加过滤器:

    php Route::get('admin-only', array('before' => 'checkAdmin', 'after' => 'logAdmin', function() { return 'Hello there, admin!'; }));

  2. 在我们的filters.php文件中添加两个过滤器:

    ```php Route::filter('checkAdmin', function() { if ('admin' !== Session::get('user_type')) { return 'You are not an Admin. Go Away!'; } });

    Route::filter('logAdmin', function() { Log::info('Admin logged in on ' . date('m/d/Y')); }); ```

  3. 创建一个我们可以设置管理会话的路径:

    php Route::get('set-admin', function() { Session::put('user_type', 'admin'); return Redirect::to('admin-only'); });

  4. 通过转到http://your-server/admin-only(其中your-server是您的服务器的网址)来测试路线,并注意结果。然后,去set-admin看看那些结果。

  5. 转到app/storage/logs目录,查看日志文件。

它是如何工作的...

在我们的admin-only路线中,不是仅仅添加闭包,而是添加一个数组,闭包作为的最后一个参数。出于我们的目的,我们希望在访问路线之前检查user_type会话是否设置为admin。我们还希望在每次有人访问路由时记录日志,但仅在页面处理完毕后。

在我们的before过滤器中,我们对一个会话进行简单的检查,如果该会话不等于admin,我们返回一个通知并阻止路由返回它的消息。如果会话等于admin,则路由照常进行。

访问路线后,我们会创建一个访问日志以及访问路线的日期。

此时,如果我们在浏览器中进入admin-only,则before过滤器将会启动并显示错误信息。然后,如果我们转到日志目录并查看日志,它会显示尝试的时间、日志消息的名称和响应。对我们来说,这将表明你不是管理员。走开!

为了使路线可访问,我们创建了另一条路线,它简单地设置了我们想要的会话,并重定向回我们的admin-only页面。如果我们访问set-admin,它会自动指引我们到admin-only,并显示成功页面。此外,如果我们查看日志,我们将看到我们成功尝试的线条。

还有更多...

这是一种非常基本的身份验证方法,只是为了显示过滤器的有用性。为了更好地进行身份验证,请使用 Laravel 的内置方法。

使用路由组

创建 web 应用时,我们可能会发现一些路由需要相同的 URL 前缀或过滤器。使用 Laravel 的路线组,我们可以轻松地将这些应用于多条路线。

做好准备

对于这个食谱,我们只需要一个标准安装的 Laravel。

怎么做…

要完成此配方,请遵循以下步骤:

  1. 在我们的app/filters.php文件中,创建一个过滤器来检查用户:

    php Route::filter('checkUser', function() { if ('user' !== Session::get('profile')) { return 'You are not Logged In. Go Away!'; } });

  2. app/routes.php文件中,创建一条可以设置我们的配置文件会话的路线:

    php Route::get('set-profile', function() { Session::set('profile', 'user'); return Redirect::to('profile/user'); });

  3. routes.php中,创建我们的路线组:

    php Route::group(array('before' => 'checkUser', 'prefix' => 'profile'), function() { Route::get('user', function() { return 'I am logged in! This is my user profile.'; }); Route::get('friends', function() { return 'This would be a list of my friends'; }); });

  4. 在我们的浏览器中,我们接着进入http://path/to/our/server/profile/user,在那里我们会得到一个错误。如果我们随后转到http://path/to/our/server/set-profile,它将重定向我们并显示正确的页面。

它是如何工作的...

我们需要做的第一件事是创建一个过滤器。这个简单的过滤器将检查一个会话名称profile,看它是否等于user。如果没有,它不会让我们继续前进。

回到我们的路线,然后我们创建一条路线,它将为我们设置profile会话,然后将我们重定向到路线组。设置会话通常会在登录后完成,但这里我们只是测试以确保它能工作。

最后,我们创建我们的路线组。对于这个组,我们希望其中的每条路线在允许访问之前都要通过checkUser过滤器。我们也希望这些路线有profile/在他们之前。我们通过在调用组的闭包之前将它们添加到数组中来实现这一点。现在,我们在这个组内创建的任何路由都必须通过过滤器,并且可以使用profile前缀进行访问。

构建一个有路线的 RESTful API

现代网络应用的一个共同需求是拥有第三方可以运行查询的应用编程接口。由于 Laravel 是以 RESTful 模式为焦点构建的,所以用很少的工作就可以很容易地构建一个完整的 API。

做好准备

对于这个配方,我们需要一个标准的 Laravel 安装,并在我们的应用中绑定一个正确配置的 MySQL 数据库。

怎么做...

要完成此配方,请遵循以下步骤:

  1. 打开命令行,转到 Laravel 安装的根目录,使用以下命令为我们的表创建一个迁移:

    php php artisan migrate:make create_shows_table

  2. app/database/migrations目录中,找到类似于2012_12_01_222821_create_shows_table.php的文件,为我们的表创建如下模式:

    ```php <?php

    use Illuminate\Database\Migrations\Migration;

    class CreateShowsTable extends Migration {

    /* * Run the migrations. * * @return void / public function up() { Schema::create('shows', function($table) { $table->increments('id'); $table->string('name'); $table->integer('year'); $table->timestamps(); });

    }

    /* * Reverse the migrations. * * @return void / public function down() { Schema::drop('shows'); } } ```

  3. 回到命令行,按如下方式运行迁移:

    php php artisan migrate

  4. 创建另一个迁移来添加一些测试数据:

    php php artisan migrate:make add_shows_data

  5. app/database/migrations文件夹中,打开add_shows_data文件,添加如下查询:

    ```php <?php

    use Illuminate\Database\Migrations\Migration;

    class AddShowsData extends Migration {

    /* * Run the migrations. * * @return void / public function up() { $shows = array( array( 'name' => 'Happy Days', 'year' => 1981 ), array( 'name' => 'Seinfeld', 'year' => 1998 ), array( 'name' => 'Arrested Development', 'year' => 2006 ) ); DB::table('shows')->insert($shows); }

    /* * Reverse the migrations. * * @return void / public function down() { DB::table('shows')->delete(); } } ```

  6. 在命令行中,按照如下方式运行迁移:

    php php artisan migrate

  7. app/models目录下,创建一个名为Show.php的文件,并添加以下代码:

    php <?php class Show extends Eloquent { protected $table = 'shows'; }

  8. routes.php中,创建一条路线返回所有节目或单个节目的 JSON,如下所示:

    php Route::get('show/{id?}', function($id = null) { if (!$id) { return Show::all(); } if ($show = Show::find($id)) { return $show; } });

  9. 创建一条路线,添加新的显示如下:

    php Route::post('show', function() { $show = new Show; $show->name = Input::get('name'); $show->year = Input::get('year'); $show->save(); return $show; });

  10. 创建将删除记录的路线:

    php Route::delete('show/{id}', function($id) { if ($show = Show::find($id)) { $show->delete(); return json_encode(array('message' => 'Record ' . $id. ' deleted.')); } });

  11. 创建路线以更新记录:

    ```php Route::put('show/{id}', function($id) { if ($show = Show::find($id)) { if (Input::get('name')) { $show->name = Input::get('name'); } if (Input::get('year')) { $show->year = Input::get('year'); }

       $show->save();
       return $show;
    

    } }); ```

  12. 制作路线来保存我们的添加和编辑show form :

    ```php Route::get('show-form/{id}', function($id = null) { $data = array();

    if ($id) { if (!$show = Show::find($id)) { return 'No show with that ID'; }

       $data = array(
             'id'     => $id,
             'method' => 'PUT',
             'name'   => $show->name,
             'year'   => $show->year
        );
    

    } else { $data = array( 'id' => '', 'method' => 'POST', 'name' => '', 'year' => '' ); } return View::make('show-form', $data); }); ```

  13. 制作一个路线来展示一个列表,这样我们就可以删除一个展示:

    php Route::get('show-delete', function() { $shows = Show::all(); return View::make('show-delete')->with('shows',$shows); });

  14. 在我们的app/views文件夹中,创建一个名为show-form.php的文件,并在其中添加以下代码:

    php <?php echo Form::open(array('url' => 'show/' . $id, 'method' => $method)) ?> <?php echo Form::label('name', 'Show Name: ') . Form::text('name', $name) ?> <br> <?php echo Form::label('year', 'Show Year: ') . Form::text('year', $year) ?> <br> <?php echo Form::submit() ?> <?php echo Form::close() ?>

  15. 然后,在app/views中,创建一个名为show-delete.php的文件,并在其中添加以下代码:

    php <?php foreach ($shows as $show): ?> <?php echo Form::open(array('url' => 'show/' . $show->id, 'method' => 'DELETE')) ?> <?php echo Form::label('name', 'Show Name: ') . $show->name ?> <?php echo Form::submit('Delete') ?> <?php echo Form::close() ?> <?php endforeach; ?>

  16. 通过浏览器中的show-formshow-delete路线进行测试。

它是如何工作的...

我们的第一步是用我们想要使用的数据创建我们的表。使用 artisan 和迁移,我们创建一个 shows 表,然后添加一些测试数据。

对于我们的路线,我们将响应四个不同的 HTTP 动词,GETPOSTPUTDELETE,但都在同一个 URL,showGET请求将用于两个目的。首先,如果 URL 中没有传递 ID,它将显示数据库中的整个列表。第二,如果有一个 ID,它将显示单个记录。通过直接返回雄辩对象,它将自动获取我们的对象并将其显示为 JSON。

我们的下一条路线响应POST请求,并将在数据库中添加一条新记录。然后,它将显示保存为 JSON 的记录。

然后,我们添加一条响应 DELETE请求的路线。它采用id参数,删除记录,并显示删除成功的 JSON。

最后,我们有一个响应带有参数idPUT请求的路线。此路由将加载传入标识的记录,然后编辑值。如果更新正确,它会显示更新记录的 JSON。

为了显示正在运行的应用编程接口,我们需要创建一个表单来添加和更新记录。我们的show-form路由检查是否传入了一个标识,如果是,它使用PUT方法创建一个表单,并将记录的值加载到字段中。如果没有设置标识,我们使用 POST方法创建一个空白表单。

如果我们想删除一条记录,我们的show-delete路线将显示一个显示列表,并且在每个显示旁边有一个删除按钮。这些按钮实际上是使用DELETE方法的表单的一部分。

我们也可以在命令行中使用curl测试路线。例如,要获取完整列表,请使用以下代码行:

curl -X GET http://path/to/our/app/show

要发布到应用编程接口,请使用以下代码行:

curl --data "name=Night+Court&year=1984" http://path/to/our/app/show

还有更多...

请记住,这个 API 示例非常基础。为了使它更好,每当我们添加或更新记录时,我们都需要添加一些验证。加入某种身份验证也是一个好主意,这样公众就不能更改我们的表和删除记录。

我们也可以使用 Laravel 足智多谋的控制器来完成类似的事情。关于这些的更多信息可以在http://laravel.com/docs/controllers#resource-controllers的文档中找到。

使用命名路线

可能有些时候我们需要更改路线名称。在一个大型网站上,如果我们有多个链接指向不正确的路线,这可能会导致很多问题。Laravel 提供了一种易于使用的方法来为我们的路线命名,因此我们永远不必担心它们是否会改变。

做好准备

对于这个食谱,我们需要一个标准的 Laravel 安装。

怎么做...

要完成此配方,请遵循以下步骤:

  1. 在我们的routes.php文件中,创建一个命名路线如下:

    php Route::get('main-route', array('as' => 'named', function() { return 'Welcome to ' . URL::current(); }));

  2. 创建一条路由,执行到指定路由的简单重定向:

    php Route::get('redirect', function() { return Redirect::route('named'); });

  3. 创建显示指定路线链接的路线:

    php Route::get('link', function() { return '<a href="' . URL::route('named') . '">Link!</a>'; });

  4. 在浏览器中,访问http://your-server/redirecthttp://your-server/link(其中your-server是服务器的网址)并注意到它们将我们发送到main-route路线。

  5. 现在,将main-route路线更名为new-route :

    php Route::get('new-route', array('as' => 'named', function() { return 'Welcome to ' . URL::current(); }));

  6. 在浏览器中,访问重定向链接路线,看看他们现在把我们送到哪里。

它是如何工作的...

可能有些时候你的路线需要改变;例如,如果客户有一个博客,但希望路由“帖子”变成“文章”。如果我们在整个网站上都有指向“帖子”路线的链接,这将意味着我们需要找到每个文件,并确保它们已被更改。通过使用命名路由,我们可以将路由重命名为我们想要的任何名称,只要我们的所有链接都指向该名称,所有内容都会保持更新。

在我们的例子中,我们有路线main-route并将其命名为named。现在,如果我们想链接或重定向到路线,我们可以使用route()指向指定的路线。然后,如果我们将路线更改为new-route并重新检查那些链接,它将自动转到更改的路线。

在路线中使用子域

许多现代的网络应用为他们的用户提供定制的内容,包括给他们一个可以访问他们内容的定制子域。例如,我们可能希望提供http://username.example.com,而不是用户的个人资料页面为http://example.com/users/37。通过更改一些 DNS 和 Apache 设置,我们可以轻松地在 Laravel 中提供相同的功能。

做好准备

对于这个食谱,我们需要访问我们的域名系统设置和我们的服务器的 Apache 配置。我们还需要一个正确配置的 MySQL 数据库和一个标准的 Laravel 安装。在整个食谱中,我们将使用example.com作为域名。

怎么做...

要完成此配方,请遵循以下步骤:

  1. 在我们域名的 DNS 中,我们需要为子域添加一个使用通配符的“A”记录,如*.example.com,然后将其指向我们服务器的 IP 地址。
  2. 打开 Apache 的httpd.conf文件,向其中添加一个虚拟主机,如下所示:

    php <VirtualHost *:80> ServerName example.com ServerAlias *.example.com </VirtualHost>

  3. 在命令行中,转到我们的应用路线,并为我们的names表创建一个迁移:

    php php artisan migrate:make create_names_table

  4. migrations目录下,打开create_names_table文件,添加我们的模式:

    ```php <?php

    use Illuminate\Database\Migrations\Migration;

    class CreateNamesTable extends Migration {

    /* * Run the migrations. * * @return void / public function up() { Schema::create('users', function($table) { $table->increments('id'); $table->string('name'); $table->string('full_name'); $table->timestamps(); }); }

    /* * Reverse the migrations. * * @return void / public function down() { Schema::drop('name'); } } ```

  5. 回到命令行,创建另一个迁移来添加一些测试数据:

    php php artisan migrate:make add_names_data

  6. 打开migrations目录下的add_names_data文件:

    ```php <?php

    use Illuminate\Database\Migrations\Migration;

    class AddNamesData extends Migration {

    /* * Run the migrations. * * @return void / public function up() { $names = array( array( 'name' => 'bob', 'full_name' => 'Bob Smith' ), array( 'name' => 'carol', 'full_name' => 'Carol Smith' ), array( 'name' => 'ted', 'full_name' => 'Ted Jones' ) ); DB::table('name')->insert($names); }

    /* * Reverse the migrations. * * @return void / public function down() { DB::table('name')->delete(); } } ```

  7. 在命令行中,按如下方式运行迁移:

    php php artisan migrate

  8. 基于子域

    ```php Route::get('/', function() { $url = parse_url(URL::all()); $host = explode('.', $url['host']); $subdomain = $host[0];

    $name = DB::table('name')->where('name',$subdomain)->get();

    dd($name); }); ```

    创建路线从names表获取信息 9. 在浏览器中,使用相关子域访问我们的域,如http://ted.example.com

它是如何工作的...

首先,我们需要更新我们的域名系统和服务器。在我们的域名系统中,我们创建一个通配符子域,并在我们的 Apache 配置中创建一个虚拟主机。这确保了使用的任何子域都将转到我们的主应用。

对于我们的默认路由,我们使用 PHP 的parse_url函数获取域名,将其分解成数组,并且只使用第一个元素。然后,我们可以使用子域查询数据库,并为用户创建定制的体验。

还有更多...

这个方法允许使用一条路由来处理子域,但是如果我们想使用更多的带有子域的路由,我们可以使用类似于下面的路由组:

Route::group(array('domain' => '{subdomain}.myapp.com'), function()
{
    Route::get('/', function($subdomain)
    {
        $name = DB::table('name')->where('name', $subdomain)->get();
     dd($name);

    });
});