Laravel-应用开发秘籍(全)

Laravel 应用开发秘籍(全)

原文:zh.annas-archive.org/md5/d81d8d9e8c3a4da47310e721ff4953e5

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Laravel 已经成为最快增长的 PHP 框架之一。凭借其表达性的语法和出色的文档,很容易在很短的时间内获得一个完全运行的 Web 应用程序。此外,现代 PHP 功能的使用使得 Laravel 4 版本非常容易根据我们自己的需求进行定制,也使得我们可以轻松地创建一个高度复杂的网站。它是简单和先进的完美结合。

这本书只涵盖了 Laravel 所能做的一小部分。把它看作一个起点,有代码示例可以让事情运转起来。然后自定义它们,添加到它们,或者组合它们来创建您自己的应用程序。可能性是无限的。

关于 Laravel 最好的一点是社区。如果您遇到问题并且谷歌搜索没有帮助,总会有人愿意帮助。您可以在 IRC(Freenode 上的#laravel)或论坛(forums.laravel.io)上找到乐于助人的社区成员,或者您可以联系 Twitter 上的许多 Laravel 用户。

愉快的 Laravel 之旅!

本书涵盖的内容

第一章,“设置和安装 Laravel”,涵盖了将 Laravel 设置和运行起来的各种方式。

第二章,“使用表单和收集输入”,展示了在 Laravel 中使用表单的多种方式。它涵盖了使用 Laravel 的表单类以及一些基本验证。

第三章,“验证您的应用程序”,演示了如何对用户进行身份验证。我们将看到如何使用 OAuth、OpenId 和各种社交网络进行身份验证。

第四章,“存储和使用数据”,涵盖了所有与数据相关的内容,包括如何使用除了 MySQL 数据库之外的数据源。

第五章,“使用控制器和路由处理 URL 和 API”,介绍了 Laravel 中的各种路由方法以及如何创建一个基本的 API。

第六章,“显示您的视图”,演示了在 Laravel 中视图的工作方式。我们还将整合 Twig 模板系统和 Twitter Bootstrap。

第七章,“创建和使用 Composer 包”,解释了如何在我们的应用程序中使用包,以及如何创建我们自己的包。

第八章,“使用 Ajax 和 jQuery”,提供了不同的示例,说明了如何在 Laravel 中使用 jQuery 以及如何进行异步请求。

第九章,“有效使用安全和会话”,涵盖了有关保护我们的应用程序以及如何使用会话和 cookie 的主题。

第十章,“测试和调试您的应用程序”,展示了如何在我们的应用程序中包含单元测试,使用 PHPUnit 和 Codeception。

第十一章,“部署和集成第三方服务到您的应用程序”,介绍了许多第三方服务以及我们如何将它们包含到我们的应用程序中。

你需要什么

这本书基本上需要一个工作的 LAMP 堆栈(Linux、Apache、MySQL 和 PHP)。Web 服务器是 Apache 2,可以在httpd.apache.org找到。推荐的数据库服务器是 MySQL 5.6,可以从dev.mysql.com/downloads/mysql下载。推荐的最低 PHP 版本是 5.4,可以在php.net/downloads.php找到。

对于一体化解决方案,还有一个 WAMP 服务器(www.wampserver.com/en)或 XAMMP(www.apachefriends.org/en/xampp.html)适用于 Windows,或者 MAMP(www.mamp.info/en/mamp-pro)适用于 Mac OS X。

本书适合对象

本书适用于具有中级 PHP 知识的人。了解另一个 PHP 框架或 Laravel 的第 3 版的基础知识也会有所帮助。对 MVC 结构和面向对象编程的一些了解也会有益处。

约定

本书中,您将找到许多不同类型信息的文本样式。以下是一些样式的示例,以及它们的含义解释。

文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名,显示如下:“然后,我们使用artisan命令为我们生成一个新密钥,并自动保存在正确的文件中”。

代码块设置如下:

Route::get('accounts', function()
{
  $accounts = Account::all();
  return View::make('accounts')->with('accounts', $accounts);
});

任何命令行输入或输出都会以以下方式书写:

  php artisan key:generate

新术语重要单词以粗体显示。您在屏幕上看到的单词,例如菜单或对话框中的单词,会以这种方式出现在文本中:“登录 Pagodabox 后,单击新应用选项卡”。

注意

警告或重要说明会以这样的方式出现在方框中。

提示

技巧会以这种方式出现。

第一章:设置和安装 Laravel

在本章中,我们将涵盖:

  • 将 Laravel 安装为 git 子模块

  • 在 Apache 中设置虚拟主机和开发环境

  • 创建“干净”的 URL

  • 配置 Laravel

  • 使用 Sublime Text 2 与 Laravel

  • 设置 IDE 以自动完成 Laravel 的命名空间

  • 使用自动加载程序将类名映射到其文件

  • 使用命名空间和目录创建高级自动加载程序

介绍

在本章中,我们将学习如何轻松地启动和运行 Laravel,并确保在进行任何核心更改时更新它变得简单。我们还将设置我们的开发和编码环境,以便非常高效,这样我们就可以专注于编写优秀的代码,而不必担心与我们的应用程序无关的问题。最后,我们将看一些方法,让 Laravel 自动为我们做一些工作,这样我们就能在很短的时间内扩展我们的应用程序。

将 Laravel 安装为 git 子模块

也许有一段时间,我们希望将我们的 Laravel 安装与我们的公共文件的其余部分分开。在这种情况下,将 Laravel 安装为 git 子模块将是一个解决方案。这将允许我们通过 git 更新我们的 Laravel 文件,而不影响我们的应用程序代码。

准备工作

要开始,我们应该让我们的开发服务器运行,并安装 git。在服务器的 web 目录中,创建一个myapp目录来保存我们的文件。安装将在命令行中完成。

操作步骤...

要完成这个步骤,请按照以下步骤进行:

  1. 在您的终端或命令行中,导航到myapp的根目录。第一步是初始化 git 并下载我们的项目文件:
**$ git init**
**$ git clone git@github.com:laravel/laravel.git**

  1. 由于我们只需要public目录,所以移动到/laravel并删除其他所有内容:
**$ cd laravel**
**$ rm –r app bootstrap vendor**

  1. 然后,回到根目录,创建一个framework目录,并将 Laravel 添加为子模块:
**$ cd ..**
**$ mkdir framework**
**$ cd framework**
**$ git init**
**$ git submodule add https://github.com/laravel/laravel.git**

  1. 现在我们需要运行 Composer 来安装框架:
**php composer.phar install**

提示

有关安装 Composer 的更多信息,请访问getcomposer.org/doc/00-intro.md。本书的其余部分将假定我们正在使用composer.phar,但我们也可以将其全局添加,并通过键入composer来简单调用它。

  1. 现在,打开/laravel/public/index.php并找到以下行:
**require __DIR__.'/../bootstrap/autoload.php';**
**$app = require_once __DIR__.'/../bootstrap/start.php';**

  1. 将前面的行改为:
**require __DIR__.'/../../framework/laravel/bootstrap/autoload.php';**
**$app = require_once __DIR__.'/../../framework/laravel/bootstrap/start.php';**

它是如何工作的...

对许多人来说,简单运行git clone就足以让他们的项目运行起来。然而,由于我们希望我们的框架作为一个子模块,我们需要将这些文件与我们的项目分开。

首先,从 GitHub 下载文件,由于我们不需要任何框架文件,我们可以删除除了我们的公共文件夹之外的所有内容。然后,在framework目录中创建我们的子模块,并下载所有内容。完成后,我们运行composer install来安装所有供应商包。

为了将框架连接到我们的应用程序,我们修改/laravel/public/index.php并将require路径更改为我们的框架目录。这将让我们的应用程序准确地知道框架文件的位置。

还有更多...

一个替代方案是将public目录移动到我们服务器的根目录。然后,在更新我们的index.php文件时,我们将使用__DIR__ . '/../framework/laravel/bootstrap'来正确包含所有内容。

在 Apache 中设置虚拟主机和开发环境

在开发我们的 Laravel 应用程序时,我们需要一个 web 服务器来运行所有内容。在 PHP 5.4 及更高版本中,我们可以使用内置的 web 服务器,但如果我们需要一些更多的功能,我们将需要一个完整的 web 堆栈。在这个步骤中,我们将在 Windows 上使用 Apache 服务器,但任何带有 Apache 的操作系统都将类似。

准备工作

这个步骤需要一个最新版本的 WAMP 服务器,可在wampserver.com上找到,尽管基本原则适用于 Windows 上的任何 Apache 配置。

操作步骤...

要完成这个步骤,请按照以下步骤进行:

  1. 打开 WAMP Apache httpd.conf文件。它通常位于C:/wamp/bin/apache/Apach2.#.#/conf

  2. 找到#Include conf/extra/httpd-vhosts.conf一行,并删除第一个#

  3. 转到extra目录,打开httpd-vhosts.conf文件,并添加以下代码:

<VirtualHost *:80>
    ServerAdmin {your@email.com}
    DocumentRoot "C:/path/to/myapp/public"
    ServerName myapp.dev
    <Directory "C:/path/to/myapp/public">
        Options Indexes FollowSymLinks
        AllowOverride all
        # onlineoffline tag - don't remove
        Order Deny,Allow
        Deny from all
        Allow from 127.0.0.1
    </Directory>
</VirtualHost>
  1. 重新启动 Apache 服务。

  2. 打开 Windows 主机文件,通常在C:/Windows/System32/drivers/etc,并在文本编辑器中打开hosts文件。

  3. 在文件底部添加一行127.0.0.1 myapp.dev

它是如何工作的...

首先,在 Apache 配置文件httpd.conf中,我们取消注释允许文件包含vhosts配置文件的行。您可以直接在httpd.conf文件中包含代码,但这种方法可以使事情更有条理。

httpd-vhosts.conf文件中,我们添加我们的 VirtualHost 代码。DocumentRoot告诉服务器文件的位置,ServerName是服务器将查找的基本 URL。由于我们只想在本地开发中使用这个,我们确保只允许通过 IP127.0.0.1访问本地主机。

hosts文件中,我们需要告诉 Windows 为myapp.dev URL 使用哪个 IP。重新启动 Apache 和我们的浏览器后,我们应该能够转到http://myapp.dev并查看我们的应用程序。

还有更多...

虽然这个配方特定于 Windows 和 WAMP,但同样的想法可以应用于大多数 Apache 安装。唯一的区别将是httpd.conf文件的位置(在 Linux Ubuntu 中,它在/etc/apache2中)和 DocumentRoot 的public目录的路径(在 Ubuntu 中,它可能类似于/var/www/myapp/public)。Linux 和 Mac OS X 的hosts文件将位于/etc/hosts中。

创建“干净”的 URL

在安装 Laravel 时,我们将使用的默认 URL 是http://{your-server}/public。如果我们决定删除/public,我们可以使用 Apache 的mod_rewrite来更改 URL。

准备工作

对于这个配方,我们只需要一个新安装的 Laravel 和一切都在正确配置的 Apache 服务器上运行。

如何做...

要完成这个配方,请按照以下步骤操作:

  1. 在我们应用程序的根目录中,添加一个.htaccess文件并使用此代码:
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>
  1. 转到http://{your-server}并查看您的应用程序。

它是如何工作的...

这段简单的代码将接受我们在 URL 中添加的任何内容并将其指向public目录。这样,我们就不需要手动输入/public

还有更多...

如果我们决定将此应用程序移至生产环境,这不是完成任务的最佳方式。在那种情况下,我们只需将文件移出 Web 根目录,并将/public作为我们的根目录。

配置 Laravel

安装 Laravel 后,它几乎可以立即使用,几乎不需要配置。但是,有一些设置我们要确保更新。

准备工作

对于这个配方,我们需要一个常规的 Laravel 安装。

如何做...

要完成这个配方,请按照以下步骤操作:

  1. 打开/app/config/app.php并更新这些行:
'url' => 'http://localhost/,
'locale' => 'en',
'key' => 'Seriously-ChooseANewKey',
  1. 打开app/config/database.php并选择您首选的数据库:
'default' => 'mysql',
'connections' => array(
    'mysql' => array(
        'driver'    => 'mysql',
        'host'      => 'localhost',
        'database'  => 'database',
        'username'  => 'root',
        'password'  => '',
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        ),
    ),
  1. 在命令行中,转到应用程序的根目录,并确保storage文件夹是可写的:
**chmod –R 777 app/storage**

它是如何工作的...

大部分配置将在/app/config/app.php文件中进行。虽然设置 URL 并不是必需的,而且 Laravel 在没有设置的情况下也能很好地解决这个问题,但最好是尽量减少框架的工作量。接下来,我们设置我们的位置。如果我们选择在应用程序中提供本地化,这个设置将是我们的默认设置。然后,我们设置我们的应用程序密钥,因为最好不要保留默认设置。

接下来,我们设置将使用的数据库驱动程序。Laravel 默认提供四种驱动程序:mysql、sqlite、sqlsrv(MS SQL Server)和 pgsql(Postgres)。

最后,我们的app/storage目录将用于保存任何临时数据,例如会话或缓存,如果我们选择的话。为了允许这一点,我们需要确保应用程序可以写入该目录。

还有更多...

要轻松创建一个安全的应用程序密钥,删除默认密钥并将其留空。然后,在命令行中,转到应用程序根目录并键入:

**php artisan key:generate**

这将创建一个独特且安全的密钥,并自动保存在您的配置文件中。

使用 Sublime Text 2 与 Laravel

用于编码的最受欢迎的文本编辑器之一是 Sublime Text。Sublime 具有许多功能,使编码变得有趣,通过插件,我们可以添加特定于 Laravel 的功能来帮助我们的应用程序。

准备工作

Sublime Text 2 是一款非常可扩展的流行代码编辑器,使编写代码变得轻松。可以从www.sublimetext.com/2下载评估版本。

我们还需要在 Sublime 中安装并启用 Package Control 包,可以在wbond.net/sublime_packages/package_control/installation找到。

操作步骤...

按照以下步骤进行操作:

  1. 在菜单栏中,转到首选项然后包控制操作步骤...

  2. 选择安装包操作步骤...

  3. 搜索laravel以查看列表。选择Laravel 4 Snippets并让其安装。安装完成后,选择Laravel-Blade并安装它。

工作原理...

Sublime Text 2 中的 Laravel 片段大大简化了编写常见代码,并且几乎包括了我们在应用程序开发中所需的一切。例如,当创建路由时,只需开始输入Route,然后会弹出一个列表,允许我们选择我们想要的路由,然后自动完成我们需要的其余代码。

工作原理...

还有更多...

安装 Laravel-Blade 包对于使用 Laravel 自带的 Blade 模板系统非常有帮助。它可以识别文件中的 Blade 代码,并自动突出显示语法。

设置 IDE 以自动完成 Laravel 的命名空间

大多数IDEs(集成开发环境)在程序的一部分中具有某种形式的代码完成。为了使 Laravel 的命名空间自动完成,我们可能需要帮助它识别命名空间是什么。

准备工作

对于这个操作,我们将在 NetBeans IDE 中添加命名空间,但是在其他 IDE 中的过程类似。

操作步骤...

按照以下步骤完成此操作:

  1. 下载列出 Laravel 命名空间的预制文件:gist.github.com/barryvdh/5227822

  2. 在计算机的任何位置创建一个文件夹来保存此文件。为了我们的目的,我们将文件添加到C:/ide_helper/ide_helper.php操作步骤...

  3. 在使用 Laravel 框架创建项目后,转到文件 | 项目属性 | PHP 包含路径操作步骤...

  4. 单击添加文件夹...,然后添加C:/ide_helper文件夹。

  5. 现在,当我们开始输入代码时,IDE 将自动建议完成的代码:操作步骤...

工作原理...

一些 IDE 需要帮助理解框架的语法。为了让 NetBeans 理解,我们下载了所有 Laravel 类和选项的列表。然后,当我们将其添加到包含路径时,NetBeans 将自动检查文件并显示自动完成选项。

还有更多...

我们可以使用 Composer 自动下载和更新文档。有关安装说明,请访问github.com/barryvdh/laravel-ide-helper

使用 Autoloader 将类名映射到其文件

使用 Laravel 的 ClassLoader,我们可以轻松地在我们的代码中包含任何自定义类库,并使它们随时可用。

准备工作

对于这个操作,我们需要设置一个标准的 Laravel 安装。

操作步骤...

要完成此操作,请按照以下步骤进行操作:

  1. 在 Laravel 的/app目录中,创建一个名为custom的新目录,其中将保存我们的自定义类。

  2. custom目录中,创建一个名为MyShapes.php的文件,并添加以下简单代码:

<?php
class MyShapes {
    public function octagon() 
    {
        return 'I am an octagon';
    }
}
  1. /app/start目录中,打开global.php并更新ClassLoader,使其看起来像这样:
ClassLoader::addDirectories(array(

    app_path().'/commands',
    app_path().'/controllers',
    app_path().'/models',
    app_path().'/database/seeds',
    app_path().'/custom',

));
  1. 现在我们可以在应用程序的任何部分使用该类。例如,如果我们创建一个路由:
Route::get('shape', function()
{
    $shape = new MyShapes;
    return $shape->octagon();
});

它是如何工作的...

大多数情况下,我们会使用 Composer 向我们的应用程序添加包和库。但是,可能有一些库无法通过 Composer 获得,或者我们想要保持独立的自定义库。为了实现这一点,我们需要专门的位置来保存我们的类库;在这种情况下,我们创建一个名为custom的目录,并将其放在我们的app目录中。

然后我们添加我们的类文件,确保类名和文件名相同。这既可以是我们自己创建的类,也可以是我们需要使用的传统类。

最后,我们将目录添加到 Laravel 的 ClassLoader 中。完成后,我们将能够在应用程序的任何地方使用这些类。

另请参阅

  • 使用命名空间和目录创建高级自动加载器

使用命名空间和目录创建高级自动加载器

如果我们想确保我们的自定义类不会与应用程序中的任何其他类发生冲突,我们需要将它们添加到命名空间中。使用 PSR-0 标准和 Composer,我们可以轻松地将这些类自动加载到 Laravel 中。

准备工作

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

如何做...

要完成这个配方,请按照以下步骤进行:

  1. /app目录中,创建一个名为custom的新目录,并在custom中创建一个名为Custom的目录,在Custom中创建一个名为Shapes的目录。

  2. /app/custom/Custom/Shapes目录中,创建一个名为MyShapes.php的文件,并添加以下代码:

<?php namespace Custom\Shapes;

class MyShapes {
    public function triangle() 
    {
        return 'I am a triangle';
    }
}
  1. 在应用程序的根目录中,打开composer.json文件并找到autoload部分。更新它使其看起来像这样:
"autoload": {
    "classmap": [
    "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php",
    ],
    "psr-0": {
        "Custom": "app/custom"
    }
}
  1. 在命令行中运行composer上的dump-autoload
**php composer.phar dump-autoload**

  1. 现在我们可以通过其命名空间调用该类。例如,如果我们创建一个路由:
Route::get('shape', function()
{
    $shape = new Custom\Shapes\MyShapes;
    return $shape->triangle();
});

它是如何工作的...

命名空间是 PHP 的一个强大补充,它允许我们使用类而不必担心它们的类名与其他类名发生冲突。通过在 Laravel 中自动加载命名空间,我们可以创建一组复杂的类,而不必担心类名与其他命名空间发生冲突。

为了我们的目的,我们通过 composer 加载自定义类,并使用 PSR-0 标准进行自动加载。

还有更多...

为了进一步扩展我们的命名空间类的使用,我们可以使用IoC将其绑定到我们的应用程序。更多信息可以在 Laravel 文档中找到laravel.com/docs/ioc

另请参阅

  • 使用自动加载器将类名映射到其文件的配方

第二章:使用表单和收集输入

在本章中,我们将涵盖:

  • 创建一个简单的表单

  • 收集表单输入以在另一页上显示

  • 验证用户输入

  • 创建一个文件上传器

  • 验证文件上传

  • 创建自定义错误消息

  • 向表单添加“蜜罐”

  • 使用 Redactor 上传图像

  • 使用 Jcrop 裁剪图像

  • 创建一个自动完成文本输入

  • 制作一个验证码样式的垃圾邮件捕捉器

介绍

在本章中,我们将学习如何在 Laravel 中使用表单,以及如何完成一些典型的任务。我们将从一些简单的表单验证和文件上传开始,然后继续将一些前端工具,如 Redactor 和 jCrop,整合到 Laravel 中。

创建一个简单的表单

任何 Web 应用程序的最基本方面之一是表单。Laravel 提供了一种简单的方法来为我们的表单构建 HTML。

准备工作

要开始,我们需要一个全新的 Laravel 安装。

操作步骤...

要完成此示例,请按照以下步骤操作:

  1. app/views文件夹中,创建一个新的userform.php文件。

  2. routes.php中,创建一个路由来加载视图:

Route::get(userform, function()
{
    return View::make('userform');
});
  1. userform.php视图中,使用以下代码创建一个表单:
<h1>User Info</h1>
<?= Form::open() ?>
<?= Form::label('username', 'Username') ?>
<?= Form::text('username') ?>
<br>
<?= Form::label('password', 'Password') ?>
<?= Form::password('password') ?>
<br>
<?= Form::label('color', 'Favorite Color') ?>
<?= Form::select('color', array('red' => 'red', 'green' =>'green', 'blue' => 'blue')) ?>
<br>
<?= Form::submit('Send it!') ?>
<?= Form::close() ?>

通过转到http://{your-server}/userform(其中{your-server}是您的服务器的名称)在 Web 页面中查看您的表单。

工作原理...

对于这个任务,我们使用 Laravel 内置的Form类创建了一个简单的表单。这使我们能够轻松地使用最少的代码创建表单元素,并且它符合 W3C(万维网联盟)标准。

首先,我们打开表单。Laravel 会自动创建<form>html,包括 action、method 和 accept-charset 参数。当没有传递选项时,默认操作是当前 URL,默认方法是POST,字符集取自应用配置文件。

接下来,我们创建普通文本和密码输入字段,以及它们的标签。标签中的第一个参数是文本字段的名称,第二个参数是要打印的实际文本。在表单构建器中,标签应该出现在实际表单输入之前。

表单选择需要第二个参数,即下拉框中值的数组。在本例中,我们使用'key' => 'value'语法创建一个数组。如果我们想创建选项组,我们只需要创建嵌套数组。

最后,我们创建了提交按钮并关闭了表单。

还有更多...

大多数 Laravel 的表单方法也可以包括默认值和自定义属性(类、ID 等)的参数。如果我们不想使用特定的方法,我们也可以对许多字段使用Form::input()。例如,我们可以使用Form::input('submit', NULL, 'Send it!')来创建一个提交按钮。

另请参阅

  • 收集表单输入以在另一页上显示示例

收集表单输入以在另一页上显示

用户提交表单后,我们需要能够获取该信息并将其传递到另一页。这个示例展示了我们如何使用 Laravel 的内置方法来处理我们的 POST 数据。

准备工作

我们需要从创建一个简单的表单部分设置简单的表单。

操作步骤...

按照以下步骤完成此示例:

  1. 创建一个路由来处理表单中的 POST 数据:
Route::post('userform', function()
{
    // Process the data here
    return Redirect::to('userresults')-
        >withInput(Input::only('username', 'color'));
});

  1. 创建一个重定向到的路由,并显示数据:
Route::get('userresults', function()
{
    return 'Your username is: ' . Input::old('username')
        . '<br>Your favorite color is: '
        . Input::old('color');
});

工作原理...

在我们的简单表单中,我们将数据 POST 回相同的 URL,因此我们需要创建一个接受相同路径的POST路由。这是我们将对数据进行任何处理的地方,包括保存到数据库或验证输入。

在这种情况下,我们只是想将数据传递到下一页。有许多方法可以实现这一点。例如,我们可以使用Input类的flashOnly()方法:

Route::post('userform', function()
{
    Input::flashOnly('username', 'color');
    return Redirect::to('userresults');
});

但是,我们使用了 Laravel 提供的一个快捷方式,只传递了我们要求的三个表单字段中的两个。

在下一页上,我们使用Input::old()来显示闪存输入。

另请参阅

  • 创建一个简单的表单示例

验证用户输入

在大多数 Web 应用程序中,将需要某些必填的表单字段来处理表单。我们还希望确保所有电子邮件地址的格式正确,或者输入必须具有一定数量的字符。使用 Laravel 的Validator类,我们可以检查这些规则,并让用户知道是否有不正确的地方。

准备工作

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

如何做...

完成这个食谱,按照以下步骤进行:

  1. 创建一个路由来保存表单:
Route::get('userform', function()
{
    return View::make('userform');
});
  1. 创建一个名为userform.php的视图并添加一个表单:
<h1>User Info</h1>
<?php $messages =  $errors->all('<pstyle="color:red">:message</p>') ?>
<?php
foreach ($messages as $msg)
{
    echo $msg;
}
?>
<?= Form::open() ?>
<?= Form::label('email', 'Email') ?>
<?= Form::text('email', Input::old('email')) ?>
<br>
<?= Form::label('username', 'Username') ?>
<?= Form::text('username', Input::old('username')) ?>
<br>
<?= Form::label('password', 'Password') ?>
<?= Form::password('password') ?>
<br>
<?= Form::label('password_confirm', 'Retype your Password')?>
<?= Form::password('password_confirm') ?>
<br>
<?= Form::label('color', 'Favorite Color') ?>
<?= Form::select('color', array('red' => 'red', 'green' =>'green', 'blue' => 'blue'), Input::old('color')) ?>
<br>
<?= Form::submit('Send it!') ?>
<?php echo Form::close() ?>
  1. 创建一个处理我们的POST数据并验证它的路由:
Route::post('userform', function()
{
    $rules = array(
        'email' => 'required|email|different:username',
        'username' => 'required|min:6',
        'password' => 'required|same:password_confirm'
    );
    $validation = Validator::make(Input::all(), $rules);

    if ($validation->fails())
    {
        return Redirect::to('userform')-
            >withErrors($validation)->withInput();
    }

    return Redirect::to('userresults')->withInput();

});

  1. 创建一个路由来处理成功的表单提交:
Route::get('userresults', function()
{
    return dd(Input::old());
});

它是如何工作的...

在我们的表单页面中,我们首先检查是否有任何错误,并在找到错误时显示它们。在错误内部,我们可以为每个错误消息设置默认样式。我们还可以选择使用$errors->get('email')来检查并显示单个字段的错误。如果 Laravel 检测到闪存错误,$errors变量将自动创建。

接下来,我们创建我们的表单。在表单元素的最后一个参数中,我们获取Input::old(),如果验证失败,我们将使用它来存储先前的输入。这样,用户就不需要一直填写整个表单。

然后创建一个路由,表单被 POST 提交,并设置我们的验证规则。在这种情况下,我们对emailusernamepassword使用必填规则,以确保这些字段中有内容输入。

email字段还使用email规则,该规则使用 PHP 的内置FILTER_VALIDATE_EMAIL过滤器的filter_var函数。email字段也不能与username字段相同。username字段使用大小验证来检查至少六个字符。然后password字段检查password_confirm字段的值,并确保它们相同。

然后,我们创建验证器并传入所有表单数据。如果其中任何规则不符合,我们将用户导航回表单,并返回任何验证错误消息以及原始表单输入。

如果验证通过,我们使用 Laravel 的dd()辅助函数转到下一个页面,该函数使用var_dump()在页面上显示表单值。

另请参阅

  • 创建一个简单的表单食谱

创建一个文件上传程序

有时我们希望用户将文件上传到我们的服务器。这个食谱展示了 Laravel 如何通过 Web 表单处理文件上传。

准备工作

要创建一个文件上传程序,我们需要安装标准版本的 Laravel。

如何做...

完成这个食谱,按照以下步骤进行:

  1. 在我们的routes.php文件中创建一个路由来保存表单:
Route::get('fileform', function()
{
    return View::make('fileform');
});
  1. 在我们的app/views目录中创建fileform.php视图:
<h1>File Upload</h1>
<?= Form::open(array('files' => TRUE)) ?>
<?= Form::label('myfile', 'My File') ?>
<br>
<?= Form::file('myfile') ?>
<br>
<?= Form::submit('Send it!') ?>
<?= Form::close() ?>
  1. 创建一个路由来上传和保存文件:
Route::post('fileform', function()
{
    $file = Input::file('myfile');
    $ext = $file->guessExtension();
    if ($file->move('files', 'newfilename.' . $ext))
    {
        return 'Success';
    }
    else
    {
        return 'Error';
    }
});

它是如何工作的...

在我们的视图中,我们使用Form::open()并传入一个数组,其中包含'files' => TRUE,这会自动设置Form标签中的 enctype;然后我们添加一个表单字段来接受文件。在Form::open()中不使用任何其他参数,表单将使用默认的POST方法和当前 URL 的操作。Form::file()是我们接受文件的输入字段。

由于我们的表单正在提交到相同的 URL,我们需要创建一个路由来接受POST输入。$file变量将保存所有文件信息。

接下来,我们想要使用不同的名称保存文件,但首先我们需要获取上传文件的扩展名。因此,我们使用guessExtension()方法,并将其存储在一个变量中。大多数文件使用方法都可以在 Symfony 的文件库中找到。

最后,我们使用文件的move()方法将文件移动到其永久位置,第一个参数是我们将保存文件的目录;第二个是文件的新名称。

如果一切上传正确,我们显示'Success',如果不是,我们显示'Error'

另请参阅

  • 验证文件上传食谱

验证文件上传

如果我们希望允许用户通过我们的网络表单上传文件,我们可能希望限制他们上传的文件类型。使用 Laravel 的Validator类,我们可以检查特定的文件类型,甚至限制上传到特定文件大小。

准备工作

对于这个配方,我们需要一个标准的 Laravel 安装和一个示例文件来测试我们的上传。

如何做...

按照以下步骤完成这个配方:

  1. 在我们的routes.php文件中为表单创建一个路由:
Route::get('fileform', function()
{
    return View::make('fileform');
});
  1. 创建表单视图:
<h1>File Upload</h1>
<?php $messages =  $errors->all('<p style="color:red">:message</p>') ?>
<?php
foreach ($messages as $msg)
{
    echo $msg;
}
?>
<?= Form::open(array('files' => TRUE)) ?>
<?= Form::label('myfile', 'My File (Word or Text doc)') ?>
<br>
<?= Form::file('myfile') ?>
<br>
<?= Form::submit('Send it!') ?>
<?= Form::close() ?>
  1. 创建一个路由来验证和处理我们的文件:
Route::post('fileform', function()
{
    $rules = array(
        'myfile' => 'mimes:doc,docx,pdf,txt|max:1000'
    );
    $validation = Validator::make(Input::all(), $rules);

    if ($validation->fails())
    {
return Redirect::to('fileform')->withErrors($validation)->withInput();
    }
    else
    {
        $file = Input::file('myfile');
        if ($file->move('files', $file->getClientOriginalName()))
        {
            return "Success";
        }
        else 
        {
            return "Error";
        }
    }
});

它是如何工作的...

我们首先创建一个用于保存我们的表单的路由,然后是表单的 html 视图。在视图顶部,如果我们在验证中得到任何错误,它们将在这里被输出。表单以Form::open (array('files' => TRUE))开始,这将为我们设置默认的操作、方法和enctype

接下来,我们创建一个路由来捕获 POST 数据并验证它。我们将一个$rules变量设置为一个数组,首先检查特定的 MIME 类型。我们可以使用尽可能少或尽可能多的规则。然后我们确保文件小于 1000 千字节,或 1 兆字节。

如果文件无效,我们将用户导航回带有错误消息的表单。如果 Laravel 检测到闪存的错误消息,$error变量会自动在我们的视图中创建。如果它是有效的,我们尝试将文件保存到服务器。如果保存正确,我们将看到"Success",如果不是,我们将看到"Error"

还有更多...

文件的另一个常见验证是检查图像。为此,我们可以在我们的$rules数组中使用以下内容:

'myfile' => 'image'

这将检查文件是否是.jpg.png.gif.bmp文件。

另请参阅

  • 创建文件上传器配方

创建自定义错误消息

如果验证失败,Laravel 内置了错误消息,但我们可能希望自定义这些消息,使我们的应用程序变得独特。这个配方展示了创建自定义错误消息的几种不同方法。

准备工作

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

如何做...

要完成这个配方,请按照以下步骤:

  1. routes.php中创建一个路由来保存表单:
Route::get('myform', function()
{
    return View::make('myform');
});
  1. 创建一个名为myform.php的视图并添加一个表单:
<h1>User Info</h1>
<?php $messages =  $errors->all
    ('<p style="color:red">:message</p>') ?>
<?php
foreach ($messages as $msg) 
{
    echo $msg;
}
?>
<?= Form::open() ?>
<?= Form::label('email', 'Email') ?>
<?= Form::text('email', Input::old('email')) ?>
<br>
<?= Form::label('username', 'Username') ?>
<?= Form::text('username', Input::old('username')) ?>
<br>
<?= Form::label('password', 'Password') ?>
<?= Form::password('password') ?>
<br>
<?= Form::submit('Send it!') ?>
<?= Form::close() ?>
  1. 创建一个路由来处理我们的 POST 数据并验证它:
Route::post('myform', array('before' => 'csrf', function()
{
    $rules = array(
        'email'    => 'required|email|min:6',
        'username' => 'required|min:6',
        'password' => 'required'
    );

    $messages = array(
        'min' => 'Way too short! The :attribute must be atleast :min characters in length.',
        'username.required' => 'We really, really need aUsername.'
    );

    $validation = Validator::make(Input::all(), $rules,$messages);

    if ($validation->fails())
    {
        return Redirect::to('myform')->withErrors($validation)->withInput();
    }

    return Redirect::to('myresults')->withInput();
}));
  1. 打开文件app/lang/en/validation.php,其中en是应用程序的默认语言。在我们的情况下,我们使用的是英语。在文件底部,更新attributes数组如下:
'attributes' => array(
    'password' => 'Super Secret Password (shhhh!)'
),
  1. 创建一个路由来处理成功的表单提交:
Route::get('myresults', function()
{
    return dd(Input::old());
});

它是如何工作的...

我们首先创建一个相当简单的表单,由于我们没有向Form::open()传递任何参数,它将把数据 POST 到相同的 URL。然后我们创建一个路由来接受POST数据并验证它。作为最佳实践,我们还在我们的post路由之前添加了csrf过滤器。这将提供一些额外的安全性,防止跨站点请求伪造。

我们在post路由中设置的第一个变量将保存我们的规则。下一个变量将保存我们希望在出现错误时使用的任何自定义消息。有几种不同的方法来设置消息。

自定义的第一个消息是min大小。在这种情况下,它将显示相同的消息,用于任何验证错误,其中有一个min规则。我们可以使用:attribute:min来保存表单字段名称和错误显示时的最小大小。

我们的第二个消息仅用于特定的表单字段和特定的验证规则。我们首先放置表单字段名称,然后是一个句号,然后是规则。在这里,我们正在检查用户名是否必填,并设置错误消息。

我们的第三个消息是在验证的语言文件中设置的。在attributes数组中,我们可以将我们的任何表单字段名称设置为显示我们想要的任何自定义文本。此外,如果我们决定自定义整个应用程序中的特定错误消息,我们可以在该文件的顶部更改默认消息。

还有更多...

如果我们查看app/lang目录,我们会看到许多翻译已经是 Laravel 的一部分。如果我们的应用程序是本地化的,我们可以选择任何语言设置自定义验证错误消息。

另请参阅

  • 创建一个简单的表单教程

向表单添加蜜罐

网络的一个悲哀现实是存在“垃圾邮件机器人”,它们搜索网络并寻找要提交垃圾邮件的表单。帮助应对这一问题的一种方法是使用一种称为蜜罐的技术。在这个教程中,我们将创建一个自定义验证来检查垃圾邮件提交。

准备工作

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

如何做...

要完成这个教程,请按照以下步骤进行:

  1. routes.php中创建一个路由来保存我们的表单:
Route::get('myform', function()
{
    return View::make('myapp');
});
  1. 在我们的app/view目录中创建一个名为myform.php的视图,并添加表单:
<h1>User Info</h1>
<?php $messages =  $errors->all('<p style ="color:red">:message</p>') ?>
<?php
foreach ($messages as $msg)
{
    echo $msg;
}
?>
<?= Form::open() ?>
<?= Form::label('email', 'Email') ?>
<?= Form::text('email', Input::old('email')) ?>
<br>
<?= Form::label('username', 'Username') ?>
<?= Form::text('username', Input::old('username')) ?>
<br>
<?= Form::label('password', 'Password') ?>
<?= Form::password('password') ?>
<?= Form::text('no_email', '', array('style' =>'display:none')) ?>
<br>
<?= Form::submit('Send it!') ?>
<?= Form::close() ?>
  1. 在我们的routes.php文件中创建一个路由来处理post数据,并对其进行验证:
Route::post('myform', array('before' => 'csrf', function()
{
    $rules = array(
        'email'    => 'required|email',
        'password' => 'required',
        'no_email' => 'honey_pot'
    );
    $messages = array(
        'honey_pot' => 'Nothing should be in this field.'
    );
    $validation = Validator::make(Input::all(), $rules,$messages);

    if ($validation->fails())
    {
        return Redirect::to('myform')->withErrors($validation)->withInput();
    }

    return Redirect::to('myresults')->withInput();
}));
  1. 在我们的routes.php文件中,创建一个自定义验证:
Validator::extend('honey_pot', function($attribute, $value,$parameters)
{
    return $value == '';
});
  1. 创建一个简单的路由用于成功页面:
Route::get('myresults', function()
{
    return dd(Input::old());
});

它是如何工作的...

我们首先创建一个相当简单的表单;因为我们没有向Form::open()传递任何参数,它将把数据 POST 到相同的 URL。在表单中,我们创建一个旨在为空的字段,但使用 CSS 隐藏它。通过将其命名为带有email一词的内容,许多垃圾邮件机器人会误以为它是一个email字段并尝试填充它。

然后,我们创建一个路由来接受post数据并对其进行验证,并在路由之前添加一个csrf过滤器。我们为我们的no_email字段添加一个自定义验证规则,以确保该字段保持为空。我们还在$messages数组中为该规则创建一个错误消息。

接下来,我们实际上在routes文件中创建我们的自定义验证规则。这个规则将从表单字段获取值,并在值为空时返回TRUE

现在,如果一个机器人试图填写整个表单,它将无法验证,因为额外的字段设计为保持为空。

还有更多...

创建自定义验证的另一种选择是使用规则size: 0,这将确保honey_pot字段的长度正好为0个字符。然而,这种方法使验证检查变得简单得多。

我们可能还希望将任何蜜罐错误重定向到另一个没有表单的页面。这样,任何自动表单提交脚本都不会继续尝试提交表单。

使用 Redactor 上传图片

有一些不同的 JavaScript 库可以将表单的文本区域转换为所见即所得的编辑器。Redactor 是一个较新的库,但编码非常好,并在短时间内获得了相当大的流行。在这个教程中,我们将把 Redactor 应用到我们的 Laravel 表单中,并创建路由以允许通过 Redactor 上传图片。

准备工作

我们需要从github.com/dybskiy/redactor-js/tree/master/redactor下载 Redactor 的副本。下载redactor.min.js并保存到public/js目录。下载redactor.css并保存到public/css目录。

如何做...

要完成这个教程,请按照以下步骤进行:

  1. 在我们的routes.php文件中创建一个路由来保存带有redactor字段的表单:
Route::get('redactor', function() 
{
    return View::make('redactor');
});
  1. 在我们的app/views目录中创建一个名为redactor.php的视图:
<!DOCTYPE html>
<html>
    <head>
        <title>Laravel and Redactor</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="css/redactor.css" />
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script src="js/redactor.min.js"></script>
    </head>
    <body>
        <?= Form::open() ?>
        <?= Form::label('mytext', 'My Text') ?>
        <br>
        <?= Form::textarea('mytext', '', array('id' =>'mytext')) ?>
        <br>
        <?= Form::submit('Send it!') ?>
        <?= Form::close() ?>
        <script type="text/javascript">
            $(function() {
                $('#mytext').redactor({
                    imageUpload: 'redactorupload'
                });
            });
        </script>
    </body>
</html>
  1. 创建一个处理图片上传的路由:
Route::post('redactorupload', function()
{
    $rules = array(
        'file' => 'image|max:10000'
    );
    $validation = Validator::make(Input::all(), $rules);
    $file = Input::file('file');
    if ($validation->fails())
    {
        return FALSE;
    }
    else
    {
        if ($file->move('files', $file->
            getClientOriginalName()))
        {
            return Response::json(array('filelink' =>
               'files/' . $file->getClientOriginalName()));
        }
        else
        {
            return FALSE;
        }
    }
});

  1. 创建另一个路由来显示我们的表单输入后。
Route::post('redactor', function() 
{
    return dd(Input::all());
});

它是如何工作的...

创建完我们的表单路由后,我们创建视图来保存我们的表单 HTML。在页面的头部,我们加载 redactor CSS,jquery 库(使用 Google 的 CDN),和 redactor JavaScript 文件。

我们的表单只有一个字段,一个名为mytext的文本区域。在我们的脚本区域中,我们在文本区域字段上初始化 Redactor,并将imageUpload参数设置为一个接受图片上传的路由或控制器。我们的设置为redactorupload,所以我们为它创建一个接受post数据的路由。

在我们的redactorupload路由中,我们进行一些验证,如果一切正常,图像将上传到我们的图像目录。要在文本区域中显示图像,它需要一个带有文件链接的 JSON 数组作为键,图像路径作为值。为此,我们将使用 Laravel 内置的Response::json方法,并传入一个带有图像位置的数组。

在我们的表单页面上,如果图像验证和上传正确,Redactor 将在文本区域内显示图像。如果我们提交,我们将看到文本包括<img>标签和图像路径。

还有更多...

虽然这个示例是专门用于图像上传的,但非图像文件上传的工作方式非常类似。唯一的真正区别是文件上传路由还应该在 JSON 输出中返回文件名。

使用 Jcrop 裁剪图像

图像编辑和处理有时可能是我们应用程序中难以实现的事情。使用 Laravel 和 Jcrop JavaScript 库,我们可以使任务变得更简单。

提示

下载示例代码

您可以从您在www.packtpub.com购买的所有 Packt 图书的帐户中下载示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便直接将文件发送到您的电子邮件。

准备工作

我们需要从deepliquid.com/content/Jcrop_Download.html下载 Jcrop 库并解压缩。将文件jquery.Jcrop.min.js放入我们的public/js目录,将jquery.Jcrop.min.cssJcrop.gif文件放入我们的public/css目录。我们将使用 Google CDN 版本的 jQuery。我们还需要确保在服务器上安装了 GD 库,以便进行图像处理。在我们的public目录中,我们需要一个图像文件夹来存储图像,并且应该对其进行可写权限设置。

如何做...

按照以下步骤完成此示例:

  1. 让我们在我们的routes.php文件中创建一个路由来保存我们的表单:
Route::get('imageform', function()
{
    return View::make('imageform');
});
  1. app/views中创建用于上传图像的表单,文件名为imageform.php
<h1>Laravel and Jcrop</h1>
<?= Form::open(array('files' => true)) ?>
<?= Form::label('image', 'My Image') ?>
<br>
<?= Form::file('image') ?>
<br>
<?= Form::submit('Upload!') ?>
<?= Form::close() ?>
  1. 创建一个路由来处理图像上传和验证:
Route::post('imageform', function()
{
    $rules = array(
        'image' => 'required|mimes:jpeg,jpg|max:10000'
    );

    $validation = Validator::make(Input::all(), $rules);

    if ($validation->fails())
    {
        return Redirect::to('imageform')->withErrors($validation);
    }
    else
    {
        $file = Input::file('image');
        $file_name = $file->getClientOriginalName();
        if ($file->move('images', $file_name))
        {
            return Redirect::to('jcrop')->with('image',$file_name);
        }
        else
        {
            return "Error uploading file";
        }
    }
});
  1. 为我们的 Jcrop 表单创建一个路由:
Route::get('jcrop', function()
{
    return View::make('jcrop')->with('image', 'images/'. Session::get('image'));
});
  1. 在我们的app/views目录中创建一个表单,我们可以在其中裁剪图像,文件名为jcrop.php
<html>
    <head>
        <title>Laravel and Jcrop</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="css/jquery.Jcrop.min.css" />
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script src="js/jquery.Jcrop.min.js"></script>
    </head>
    <body>
        <h2>Image Cropping with Laravel and Jcrop</h2>
        <img src="<?php echo $image ?>" id="cropimage">

        <?= Form::open() ?>
        <?= Form::hidden('image', $image) ?>
        <?= Form::hidden('x', '', array('id' => 'x')) ?>
        <?= Form::hidden('y', '', array('id' => 'y')) ?>
        <?= Form::hidden('w', '', array('id' => 'w')) ?>
        <?= Form::hidden('h', '', array('id' => 'h')) ?>
        <?= Form::submit('Crop it!') ?>
        <?= Form::close() ?>

        <script type="text/javascript">
            $(function() {
                $('#cropimage').Jcrop({
                    onSelect: updateCoords
                });
            });
            function updateCoords(c) {
                $('#x').val(c.x);
                $('#y').val(c.y);
                $('#w').val(c.w);
                $('#h').val(c.h);
            };
        </script>
    </body>
</html>
  1. 创建一个处理图像并显示图像的路由:
Route::post('jcrop', function()
{
    $quality = 90;

    $src  = Input::get('image');
    $img  = imagecreatefromjpeg($src);
    $dest = ImageCreateTrueColor(Input::get('w'),
        Input::get('h'));

    imagecopyresampled($dest, $img, 0, 0, Input::get('x'),
        Input::get('y'), Input::get('w'), Input::get('h'),
        Input::get('w'), Input::get('h'));
    imagejpeg($dest, $src, $quality);

    return "<img src='" . $src . "'>";
});

它是如何工作的...

我们从基本的文件上传开始;为了简化,我们只使用.jpg文件。我们使用验证来检查图像类型,以及确保文件大小在 10,000 千字节以下。文件上传后,我们将路径发送到我们的 Jcrop 路由。

在 Jcrop 路由的 HTML 中,我们创建一个带有隐藏字段的表单,该字段将保存裁剪的尺寸。JavaScript 函数updateCoords获取裁剪尺寸并更新这些隐藏字段的值。

当我们完成裁剪时,我们提交表单,我们的路由获取 POST 数据。图像通过 GD 库进行裁剪,基于发布的尺寸。然后我们覆盖图像并显示更新和裁剪后的文件。

还有更多...

虽然这个示例只涵盖了裁剪 jpg 图像,添加gifpng图像也不会很困难。我们只需要通过将文件名传递给 Laravel 并使用File::extension()来获取文件扩展名。然后,我们可以使用适当的 PHP 函数进行switchif语句。例如,如果扩展名是.png,我们将使用imagecreatefrompng()imagepng()。更多信息可以在www.php.net/manual/en/ref.image.php找到。

创建自动完成文本输入

在我们的网络表单上,可能会有时候我们想要有一个自动完成文本字段。这对于填充常见搜索词或产品名称非常方便。使用 jQueryUI 自动完成库以及 Laravel,这变得非常容易。

准备工作

在这个食谱中,我们将使用 jQuery 和 jQueryUI 的 CDN 版本;但是,如果我们想要本地拥有它们,我们也可以下载它们并将它们放在我们的public/js目录中。

如何做...

要完成这个食谱,请按照以下步骤进行:

  1. 创建一个路由来保存我们的自动完成表单:
Route::get('autocomplete', function()
{
    return View::make('autocomplete');
});
  1. app/views目录中创建一个名为autocomplete.php的视图,其中包含我们表单的 HTML 和 JavaScript:
<!DOCTYPE html>
<html>
    <head>
        <title>Laravel Autocomplete</title>
        <meta charset="utf-8">
        <link rel="stylesheet"href="//codeorigin.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" />
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script src="//codeorigin.jquery.com/ui/1.10.2/jquery-ui.min.js"></script>
    </head>
    <body>
        <h2>Laravel Autocomplete</h2>

        <?= Form::open() ?>
        <?= Form::label('auto', 'Find a color: ') ?>
        <?= Form::text('auto', '', array('id' => 'auto'))?>
        <br>
        <?= Form::label('response', 'Our color key: ') ?>
        <?= Form::text('response', '', array('id' =>'response', 'disabled' => 'disabled')) ?>
        <?= Form::close() ?>

        <script type="text/javascript">
            $(function() {
                $("#auto").autocomplete({
                    source: "getdata",
                    minLength: 1,
                    select: function( event, ui ) {
                        $('#response').val(ui.item.id);
                    }
                });
            });
        </script>
    </body>
</html>
  1. 创建一个路由,用于填充autocomplete字段的数据:
Route::get('getdata', function()
{
    $term = Str::lower(Input::get('term'));
    $data = array(
        'R' => 'Red',
        'O' => 'Orange',
        'Y' => 'Yellow',
        'G' => 'Green',
        'B' => 'Blue',
        'I' => 'Indigo',
        'V' => 'Violet',
    );
    $return_array = array();

    foreach ($data as $k => $v) {
        if (strpos(Str::lower($v), $term) !== FALSE) {
            $return_array[] = array('value' => $v, 'id' =>$k);
        }
    }
    return Response::json($return_array);
});

它是如何工作的...

在我们的表单中,我们正在创建一个文本字段来接受用户输入,该输入将用于autocomplete。还有一个禁用的文本字段,我们可以用来查看所选值的 ID。如果您对特定值有一个数字的 ID,或者以非标准方式命名,这可能会很有用。在我们的示例中,我们使用颜色的第一个字母作为 ID。

当用户开始输入时,autocomplete会向我们添加的源发送一个GET请求,使用查询字符串中的单词term。为了处理这个,我们创建一个路由来获取输入,并将其转换为小写。对于我们的数据,我们使用一个简单的值数组,但在这一点上添加数据库查询也是相当容易的。我们的路由检查数组中的值,看看是否有任何与用户输入匹配的值,如果有,就将 ID 和值添加到我们将返回的数组中。然后,我们将数组输出为 JSON,供autocomplete脚本使用。

回到我们的表单页面,当用户选择一个值时,我们将 ID 添加到禁用的响应字段中。很多时候,这将是一个隐藏字段,我们可以在提交表单时传递它。

还有更多...

如果我们想要让我们的getdata路由只能从我们的自动完成表单或其他 AJAX 请求中访问,我们可以简单地将代码包装在if (Request::ajax()) {}中,或者创建一个拒绝任何非 AJAX 请求的过滤器。

制作类似 CAPTCHA 的垃圾邮件捕捉器

对抗自动填写网络表单的“机器人”的一种方法是使用 CAPTCHA 技术。这向用户显示一个带有一些随机字母的图像;用户必须在文本字段中填写这些字母。在这个食谱中,我们将创建一个 CAPTCHA 图像,并验证用户是否已正确输入。

准备工作

我们需要一个标准的 Laravel 安装,并确保我们的服务器上安装了 GD2 库,这样我们就可以创建一个图像。

如何做...

要完成这个食谱,请按照以下步骤进行:

  1. 在我们的app目录中,创建一个名为libraries的目录,并在我们的composer.json文件中更新如下:
"autoload": {
    "classmap": [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php",
        "app/libraries"
    ]
},
  1. 在我们的app/libraries目录中,创建一个名为Captcha.php的文件,用于保存我们简单的Captcha类:
<?php
class Captcha {
    public function make() 
    {
        $string = Str::random(6, 'alpha');
        Session::put('my_captcha', $string);

        $width      = 100;
        $height     = 25;
        $image      = imagecreatetruecolor($width,$height);
        $text_color = imagecolorallocate($image, 130, 130,130);
        $bg_color   = imagecolorallocate($image, 190, 190,190);

        imagefilledrectangle($image, 0, 0, $width, $height,$bg_color);        
        imagestring($image, 5, 16, 4, $string,$text_color);

        ob_start();
        imagejpeg($image);
        $jpg = ob_get_clean();
        return "data:image/jpeg;base64,". base64_encode($jpg);
    }
}
  1. 在我们的应用程序根目录中,打开命令行界面以更新composer自动加载程序:
**php composer.phar dump-autoload**

  1. routes.php中创建一个路由来保存带有captcha的表单:
Route::get('captcha', function() 
{
    $captcha = new Captcha;
    $cap = $captcha->make();
    return View::make('captcha')->with('cap', $cap);
});
  1. app/views目录中创建我们的captcha视图,名称为captcha.php
<h1>Laravel Captcha</h1>
<?php
if (Session::get('captcha_result')) {
    echo '<h2>' . Session::get('captcha_result') . '</h2>';
}
?>
<?php echo Form::open() ?>
<?php echo Form::label('captcha', 'Type these letters:') ?>
<br>
<img src="<?php echo $cap ?>">
<br>
<?php echo Form::text('captcha') ?>
<br>
<?php echo Form::submit('Verify!') ?>
<?php echo Form::close() ?>
  1. 创建一个路由来比较captcha值和用户输入:
Route::post('captcha', function() 
{
    if (Session::get('my_captcha') !==Input::get('captcha')) {
        Session::flash('captcha_result', 'No Match.');
    } else {
        Session::flash('captcha_result', 'They Match!');
    }
    return Redirect::to('captcha');
});

它是如何工作的...

我们首先更新我们的composer.json文件,将我们的libraries目录添加到自动加载程序中。现在,我们可以将任何我们想要的类或库添加到该目录中,即使它们是自定义类或可能是一些旧代码。

为了保持简单,我们创建了一个简单的Captcha类,其中只有一个make()方法。在这个方法中,我们首先使用 Laravel 的Str:random()创建一个随机字符串,我们告诉它输出一个只包含字母的 6 个字符的字符串。然后我们将该字符串保存到会话中,以便以后用于验证。

使用字符串,我们创建了一个 100x25 像素的 jpg 图像,背景为灰色,文本为深灰色。我们不是将文件保存到服务器,而是使用输出缓冲区并将图像数据保存到一个变量中。这样,我们可以创建一个数据 URI 并发送回我们的路由。

接下来,我们需要运行 composer 的dump-autoload命令,这样我们的新类才能被应用程序使用。

在我们的captcha路由中,我们使用Captcha类来创建captcha数据 URI 并将其发送到我们的表单。对于我们的目的,表单将简单地显示图像并要求在文本字段中输入字符。

当用户提交表单时,我们将比较Captcha类创建的 Session 与用户输入。在这个示例中,我们只是检查这两个值是否匹配,但我们也可以创建一个自定义验证方法并将其添加到我们的规则中。然后我们设置一个会话来表示是否匹配,并将用户返回到 CAPTCHA 页面。

第三章:验证您的应用程序

在本章中,我们将涵盖:

  • 设置和配置 Auth 库

  • 创建一个身份验证系统

  • 在登录后检索和更新用户信息

  • 限制对某些页面的访问

  • 设置 OAuth 与 HybridAuth 包

  • 使用 OpenID 进行登录

  • 使用 Facebook 凭据登录

  • 使用 Twitter 凭据登录

  • 使用 LinkedIn 登录

介绍

许多现代网络应用程序都包括用户注册和登录的方式。为了确保我们的应用程序和用户信息的安全,我们需要确保每个用户都经过适当的身份验证。Laravel 包括一个很棒的Auth类,使得这个任务非常容易完成。在本章中,我们将从设置我们自己的身份验证系统开始,然后转向在我们的 Laravel 应用程序中使用第三方身份验证。

设置和配置 Auth 库

要使用 Laravel 的身份验证系统,我们需要确保它设置正确。在这个食谱中,我们将看到一种常见的完成设置的方式。

准备工作

要设置身份验证,我们只需要安装 Laravel 并运行一个 MySQL 实例。

如何做…

要完成这个步骤,请按照以下步骤进行:

  1. 进入您的app/config/session.php配置文件,并确保它设置为使用native
**'driver' => 'native'**

  1. app/config/auth.php配置文件的默认设置应该是可以的,但确保它们设置如下:
'driver' => 'eloquent',
'model' => 'User',
'table' => 'users',
  1. 在 MySQL 中,创建一个名为authapp的数据库,并确保在app/config/database.php配置文件中设置正确。以下是我们将使用的设置:
'default' => 'mysql',

'connections' => array(

    'mysql' => array(
        'driver'   => 'mysql',
        'host'     => 'localhost',
        'database' => 'authapp',
        'username' => 'root',
        'password' => '',
        'charset'  => 'utf8',
        'prefix'   => '',
    ),
),
  1. 我们将使用迁移和 Schema 构建器以及 Artisan 命令行来设置我们的Users表,因此我们需要创建我们的迁移表:
**php artisan migrate:install**

  1. 为我们的Users表创建迁移:
**php artisan migrate:make create_users_table**

  1. app/database/migrations目录中,将会有一个新文件,文件名是日期后跟着create_users_table.php。在那个文件中,我们创建我们的表:
<?php

use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration {

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

    }

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

}
  1. 在 Artisan 中运行迁移来创建我们的表,一切都应该设置好了:
**php artisan migrate**

它是如何工作的…

身份验证使用会话来存储用户信息,因此我们首先需要确保我们的会话配置正确。有各种各样的方式来存储会话,包括使用数据库或 Redis,但是为了我们的目的,我们将只使用native驱动程序,它利用了 Symfony 的原生会话驱动程序。

在设置身份验证配置时,我们将使用 Eloquent ORM 作为我们的驱动程序,电子邮件地址作为我们的用户名,模型将是 User。Laravel 附带了一个默认的 User 模型,并且它在开箱即用时非常好用,所以我们将使用它。为了简单起见,我们将坚持使用表名的默认配置,即模型类名的复数形式,但是如果我们想要的话,我们可以自定义它。

一旦我们确保我们的数据库配置设置正确,我们就可以使用 Artisan 来创建我们的迁移。在我们的迁移中,我们将创建我们的用户表,并存储电子邮件地址、密码、姓名和一个布尔字段来存储用户是否是管理员。完成后,我们运行迁移,我们的数据库将设置好来构建我们的身份验证系统。

创建身份验证系统

在这个食谱中,我们将创建一个简单的身份验证系统。它可以直接使用,也可以扩展以包括更多的功能。

准备工作

我们将使用设置和配置 Auth 库食谱中创建的代码作为我们身份验证系统的基础。

如何做…

要完成这个步骤,请按照以下步骤进行:

  1. 在我们的routes.php文件中创建一个路由来保存我们的注册表单:
Route::get('registration', function()
{
    return View::make('registration');
});
  1. 通过在app/views中创建一个名为registration.php的新文件来创建一个注册表单:
<!DOCTYPE html>
<html>
    <head>
        <title>Laravel Authentication - Registration</title>
        <meta charset="utf-8">
    </head>
    <body>
        <h2>Laravel Authentication - Registration</h2>
        <?php $messages =  $errors->all('<p style="color:red">:message</p>') ?>
        <?php foreach ($messages as $msg): ?>
            <?= $msg ?>
        <?php endforeach; ?>

<?= Form::open() ?>
        <?= Form::label('email', 'Email address: ') ?>
        <?= Form::text('email', Input::old('email')) ?>
        <br>
        <?= Form::label('password', 'Password: ') ?>
        <?= Form::password('password') ?>
        <br>
        <?= Form::label('password_confirm','Retype Password: ') ?>
        <?= Form::password('password_confirm') ?>
        <br>
        <?= Form::label('name', 'Name: ') ?>
        <?= Form::text('name', Input::old('name')) ?>
        <br>
        <?= Form::label('admin', 'Admin?: ') ?>
        <?= Form::checkbox('admin','true',Input::old('admin')) ?>
        <br>
        <?= Form::submit('Register!') ?>
        <?= Form::close() ?>
    </body>
</html>
  1. 创建一个路由来处理注册页面:
Route::post('registration', array('before' => 'csrf',function()
{
    $rules = array(
        'email'    => 'required|email|unique:users',
        'password' => 'required|same:password_confirm',
        'name'     => 'required'
    );
    $validation = Validator::make(Input::all(), $rules);

    if ($validation->fails())
    {
        return Redirect::to('registration')->withErrors($validation)->withInput();
    }

    $user           = new User;
    $user->email    = Input::get('email');
    $user->password = Hash::make(Input::get('password'));
    $user->name     = Input::get('name');
    $user->admin    = Input::get('admin') ? 1 : 0;
    if ($user->save())
    {
        Auth::loginUsingId($user->id);
        return Redirect::to('profile');
    }
    return Redirect::to('registration')->withInput();
}));
  1. 通过在routes.php中添加一个路由来为您的个人资料创建一个简单的页面:
Route::get('profile', function()
{
    if (Auth::check())
    {
        return 'Welcome! You have been authorized!';
    }
    else
    {
        return 'Please <a href="login">Login</a>';
    }
});
  1. routes.php中创建一个登录路由来保存登录表单:
Route::get('login', function()
{
    return View::make('login');
});
  1. 在我们的app/views目录中,创建一个名为login.php的文件:
<!DOCTYPE html>
<html>
    <head>
        <title>Laravel Authentication - Login</title>
        <meta charset="utf-8">
    </head>
    <body>
        <h2>Laravel Authentication - Login</h2>
        <?= '<span style="color:red">' .Session::get('login_error') . '</span>' ?>

        <?= Form::open() ?>
        <?= Form::label('email', 'Email address: ') ?>
        <?= Form::text('email', Input::old('email')) ?>
        <br>
        <?= Form::label('password', 'Password: ') ?>
        <?= Form::password('password') ?>
        <br>
        <?= Form::submit('Login!') ?>
        <?= Form::close() ?>
    </body>
</html>
  1. routes.php中创建一个路由来验证登录:
Route::post('login', function()
{
    $user = array(
        'username' => Input::get('email'),
        'password' => Input::get('password')
    );

    if (Auth::attempt($user))
    {
        return Redirect::to('profile');
    }

    return Redirect::to('login')->with('login_error','Could not log in.');
});
  1. routes.php中创建一个安全页面的路由:
Route::get('secured', array('before' => 'auth', function()
{
    return 'This is a secured page!';
}));

工作原理...

首先,我们创建一个相当简单的注册系统。在我们的注册表单中,我们将要求输入电子邮件地址、密码、密码确认、姓名,以及用户是否是管理员的选项。在表单字段中,我们还添加了Input::old();因此,如果表单验证不正确,我们可以重新填充字段,而无需用户重新输入所有信息。

然后我们的表单提交,添加 CSRF 过滤器,并进行一些验证。如果验证通过,我们就创建一个新的 User 模型实例,并添加表单中的字段。对于密码,我们使用Hash::make()来保护密码安全。由于我们的 admin 字段接受布尔值,我们检查 admin 复选框是否被选中;如果是,我们将值设置为1

如果一切保存正确,我们可以通过将刚创建的用户 ID 传递给Auth::loginUsingId()来自动登录用户,并将他们重定向到 profile 页面。

profile 路由的第一件事是运行Auth::check()来查看用户是否真的已登录。如果没有,它将显示一个链接到登录页面。

登录页面是一个简单的表单,要求输入电子邮件 ID 和密码。提交后,我们将这两个值放入一个数组中,并将它们传递给Auth::attempt(),它将自动对我们的密码进行哈希处理,并在数据库中查找凭据。如果成功,Auth类将设置一个会话,并将用户重定向到 profile 页面。

如果用户尝试访问安全路由,系统将把他们重定向到登录页面。使用 Laravel 的Redirect::intended(),我们可以将他们重定向回他们最初尝试访问的页面。

另请参阅

  • 设置和配置 Auth 库示例

在登录后检索和更新用户信息

用户登录后,我们需要获取关于他/她的信息。在这个示例中,我们将看到如何获取这些信息。

准备工作

我们将使用设置和配置 Auth 库创建身份验证系统示例中创建的代码作为此示例的基础。

如何做...

要完成这个示例,请按照以下步骤进行:

  1. 使用以下代码更新 profile 路由:
Route::get('profile', function()
{
    if (Auth::check())
    {
        return View::make('profile')->with('user',Auth::user());
    }
    else
    {
        return Redirect::to('login')->with('login_error','You must login first.');
    }
});
  1. 通过在app/views目录中创建一个名为profile.php的文件来创建我们的 profile 视图:
<?php echo Session::get('notify') ?  "<p style='color:
    green'>" . Session::get('notify') . "</p>" : "" ?>
<h1>Welcome <?php echo $user->name ?></h1>
<p>Your email: <?php echo $user->email ?></p>
<p>Your account was created on: <?php echo $user
    ->created_at ?></p>
<p><a href="<?= URL::to('profile-edit') ?>">Edit your
    information</a></p>
  1. 创建一个路由来保存我们的表单以编辑信息:
Route::get('profile-edit', function()
{
    if (Auth::check())
    {
        $user = Input::old() ? (object) Input::old() :Auth::user();
        return View::make('profile_edit')->with('user',$user);
    }
});
  1. 为我们的编辑表单创建一个视图:
<h2>Edit User Info</h2>
<?php $messages =  $errors->all('<p style="color:red">:message</p>') ?>
<?php foreach ($messages as $msg): ?>
    <?= $msg ?>
<?php endforeach; ?>
<?= Form::open() ?>
<?= Form::label('email', 'Email address: ') ?>
<?= Form::text('email', $user->email) ?>
<br>
<?= Form::label('password', 'Password: ') ?>
<?= Form::password('password') ?>
<br>
<?= Form::label('password_confirm', 'Retype Password: ') ?>
<?= Form::password('password_confirm') ?>
<br>
<?= Form::label('name', 'Name: ') ?>
<?= Form::text('name',  $user->name) ?>
<br>
<?= Form::submit('Update!') ?>
<?= Form::close() ?>
  1. 创建一个处理表单的路由:
Route::post('profile-edit', function()
{
    $rules = array(
        'email'    => 'required|email',
        'password' => 'same:password_confirm',
        'name'     => 'required'
    );
    $validation = Validator::make(Input::all(), $rules);

    if ($validation->fails())
    {
        return Redirect::to('profile-edit')->withErrors($validation)->withInput();
    }

    $user = User::find(Auth::user()->id);
    $user->email = Input::get('email');
    if (Input::get('password')) {
        $user->password = Hash::make(Input::get('password'));
    }
    $user->name = Input::get('name');
    if ($user->save())
    {
        return Redirect::to('profile')->with('notify','Information updated');
    }
    return Redirect::to('profile-edit')->withInput();
});

工作原理...

为了获取用户的信息并允许他/她更新信息,我们首先重新设计我们的 profile 路由。我们创建一个 profile 视图,并将Auth::user()传递给变量$user。然后,在视图文件中,我们简单地输出我们收集到的任何信息。我们还创建了一个链接到一个页面,用户可以在该页面编辑他/她的信息。

我们的 profile 编辑页面首先检查用户是否已登录。如果是,我们希望填充$user变量。由于如果有验证错误,我们将重新显示表单,所以我们首先检查Input::old()中是否有任何内容。如果没有,这可能是页面的新访问,所以我们只使用Auth::user()。如果正在使用Input::old(),我们将将其重新转换为对象,因为它通常是一个数组,并在我们的$user变量中使用它。

我们的编辑视图表单与注册表单非常相似,只是如果我们已登录,表单已经被填充。

当表单提交时,它会经过一些验证。如果一切有效,我们需要从数据库中获取用户,使用User::find()和存储在Auth::user()中的用户 ID。然后我们将我们的表单输入添加到用户对象中。对于密码字段,如果它为空,我们可以假设用户不想更改它。因此,我们只有在已经输入了内容时才会更新密码。

最后,我们保存用户信息并将其重定向回个人资料页面。

还有更多...

我们数据库中的电子邮件值可能需要是唯一的。对于本步骤,我们可能需要快速检查用户表,并确保正在更新的电子邮件地址没有在其他地方使用。

另请参阅

  • 创建身份验证系统的步骤

限制对某些页面的访问

在本步骤中,我们将探讨如何限制对应用程序中各种页面的访问。这样,我们可以使页面只对具有正确凭据的用户可见。

准备工作

我们将使用设置和配置 Auth 库创建身份验证系统的步骤中创建的代码作为本步骤的基础。

如何做...

要完成这个步骤,请按照以下步骤进行:

  1. 在我们的filters.php文件中创建一个检查已登录用户的过滤器。默认的 Laravelauth过滤器就可以了:
Route::filter('auth', function()
{
    if (Auth::guest()) return Redirect::guest('login');
});
  1. filter.php中创建一个用于检查用户是否为管理员的过滤器:
Route::filter('auth_admin', function()
{
    if (Auth::guest()) return Redirect::guest('login');
    if (Auth::user()->admin != TRUE)
        return Redirect::to('restricted');
});
  1. 创建一个我们限制给已登录用户的路由:
Route::get('restricted', array('before' => 'auth',
    function()
{
    return 'This page is restricted to logged-in users!
        <a href="admin">Admins Click Here.</a>';
}));
  1. 创建一个只限管理员访问的路由:
Route::get('admin', array('before' => 'auth_admin',function()
{
    return 'This page is restricted to Admins only!';
}));

它是如何工作的...

过滤器是 Laravel 的一个强大部分,可以用来简化许多任务。Laravel 默认的auth过滤器只是简单地检查用户是否已登录,如果没有,则将其重定向到登录页面。在我们的restricted路由中,我们添加auth过滤器在函数执行之前运行。

我们的auth_admin过滤器用于确保用户已登录,并检查用户是否设置为admin。如果没有,他/她将被重定向回普通的受限页面。

使用 HybridAuth 包设置 OAuth

有时我们可能不想担心存储用户的密码。在这种情况下,OAuth 已经成为一个流行的选择,它允许我们基于第三方服务(如 Facebook 或 Twitter)对用户进行身份验证。本步骤将展示如何设置HybridAuth包以简化 OAuth。

准备工作

对于本步骤,我们需要一个标准的 Laravel 安装和一种访问命令行界面的方法,以便我们可以使用 Artisan 命令行实用程序。

如何做...

要完成这个步骤,请按照以下步骤进行:

  1. 打开我们应用的composer.json文件,并将 HybridAuth 添加到require部分,使其看起来像这样:
"require": {
    "laravel/framework": "4.0.*",
    "hybridauth/hybridauth": "dev-master"
},
  1. 在命令行界面中,按以下方式更新 composer:
**php composer.phar update**

  1. app/config目录中,创建一个名为oauth.php的新文件:
<?php
return array(
    "base_url"   => "http://path/to/our/app/oauth/auth",
    "providers"  => array (
        "OpenID" => array ("enabled" => true),
        "Facebook" => array (
            "enabled"  => TRUE,
            "keys"     => array ("id" => "APP_ID", "secret"=> "APP_SECRET"),
            "scope"    => "email",
        ),
        "Twitter" => array (
            "enabled" => true,
            "keys"    => array ("key" => "CONSUMER_KEY","secret" => "CONSUMER_SECRET")
        ),
        "LinkedIn" => array (
            "enabled" => true,
            "keys" => array ("key" => "APP_KEY", "secret"=> "APP_SECRET")
        )
    )
);

它是如何工作的...

我们首先要将 HybridAuth 包添加到我们的 composer 文件中。现在,当我们更新 composer 时,它将自动下载并安装该包。从那时起,我们可以在整个应用程序中使用该库。

我们的下一步是设置一个配置文件。该文件以一个 URL 开头,身份验证站点将向该 URL 发送用户。该 URL 应该路由到我们将运行 HybridAuth 并进行实际身份验证的路由或控制器。最后,我们需要添加我们要对抗进行身份验证的站点的凭据。可以在 HybridAuth 网站上找到完整的站点列表:hybridauth.sourceforge.net/userguide.html

使用 OpenID 进行登录

如果我们不想在我们的应用程序中存储用户的密码,还有其他使用第三方的身份验证方法,比如 OAuth 和 OpenID。在本步骤中,我们将使用 OpenID 来登录我们的用户。

准备工作

对于本步骤,我们需要一个标准的 Laravel 安装,并完成使用 HybridAuth 包设置 OAuth的步骤。

如何做...

要完成这个步骤,请按照以下步骤进行:

  1. 在我们的app/config目录中,创建一个名为openid_auth.php的新文件:
<?php
return array(
    "base_url"   => "http://path/to/our/app/openid/auth",
    "providers"  => array (
        "OpenID" => array ("enabled" => TRUE)
    )
);
  1. 在我们的routes.php文件中,创建一个路由来保存我们的登录表单:
Route::get('login', function()
{
    return View::make('login');
});
  1. 在我们的app/views目录中,创建一个名为login.php的新视图:
<!DOCTYPE html>
<html>
    <head>
        <title>Laravel Open ID Login</title>
        <meta charset="utf-8">
    </head>
    <body>
        <h1>OpenID Login</h1>
        <?= Form::open(array('url' => 'openid', 'method' =>'POST')) ?>
        <?= Form::label('openid_identity', 'OpenID') ?>
        <?= Form::text('openid_identity', Input::old('openid_identity')) ?>
        <br>
        <?= Form::submit('Log In!') ?>
        <?= Form::close() ?>
    </body>
</html>
  1. routes.php中,创建用于运行身份验证的路由:
Route::any('openid/{auth?}', function($auth = NULL)
{
    if ($auth == 'auth') {
        try {
            Hybrid_Endpoint::process();
        } catch (Exception $e) {
            return Redirect::to('openid');
        }
        return;
    }

    try {
        $oauth = new Hybrid_Auth(app_path(). '/config/openid_auth.php');
        $provider = $oauth->authenticate('OpenID',array('openid_identifier' =>Input::get('openid_identity')));
        $profile = $provider->getUserProfile();
    }
    catch(Exception $e) {
        return $e->getMessage();
    }
    echo 'Welcome ' . $profile->firstName . ' ' . $profile->lastName . '<br>';
    echo 'Your email: ' . $profile->email . '<br>';
    dd($profile);
});

它是如何工作的...

我们首先创建一个 HybridAuth 库的配置文件,设置用户在身份验证后将被重定向的 URL,并启用 OpenID。

接下来,我们创建一个路由和一个视图,用户可以在其中输入他们想要使用的 OpenID URL。一个流行的 URL 是 Google 的 URL,所以我们建议使用 URLwww.google.com/accounts/o8/id,甚至可以自动将其设置为表单中的一个值。

提交表单后,我们应该被引导到 OpenID 网站的身份验证系统,然后重定向回我们的网站。在那里,我们可以显示用户的姓名和电子邮件 ID,并显示所有发送回来的信息。

还有更多...

有关 OpenID 提供的更多信息,请访问openid.net/developers/specs/

使用 Facebook 凭据登录

如果我们不想担心存储用户的信息和凭据,我们可以使用 OAuth 来与另一个服务进行身份验证。其中一个最受欢迎的是使用 Facebook 进行登录。使用 Laravel 和 HybridAuth 库,我们可以轻松地实现与 Facebook 的 OAuth 身份验证。

准备工作

对于这个步骤,我们需要安装 HybridAuth 包,并按照使用 HybridAuth 包设置 OAuth的步骤进行设置。

如何做...

要完成这个步骤,请按照以下步骤进行:

  1. developers.facebook.com创建一个新的应用程序。

  2. 获取 App ID 和 App Secret 密钥,在app/config目录中创建一个名为fb_auth.php的文件:

<?php
return array(
    "base_url" => "http://path/to/our/app/fbauth/auth",
    "providers" => array (
        "Facebook" => array (
            "enabled"  => TRUE,
            "keys" => array ("id" => "APP_ID", "secret" =>"APP_SECRET"),
            "scope" => "email"
        )
    )
);
  1. routes.php中创建一个用于我们的 Facebook 登录按钮的路由:
Route::get('facebook', function()
{
    return "<a href='fbauth'>Login with Facebook</a>";
});
  1. 创建一个路由来处理登录信息并显示它:
Route::get('fbauth/{auth?}', function($auth = NULL)
{
    if ($auth == 'auth') {
        try {
            Hybrid_Endpoint::process();
        } catch (Exception $e) {
            return Redirect::to('fbauth');
        }
        return;
    }

    try {
        $oauth = new Hybrid_Auth(app_path(). '/config/fb_auth.php');
        $provider = $oauth->authenticate('Facebook');
        $profile = $provider->getUserProfile();
    }
    catch(Exception $e) {
        return $e->getMessage();
    }
    echo 'Welcome ' . $profile->firstName . ' '. $profile->lastName . '<br>';
    echo 'Your email: ' . $profile->email . '<br>';
    dd($profile);
});

它是如何工作的...

获取我们的 Facebook API 凭据后,我们需要创建一个包含这些凭据和回调 URL 的配置文件。我们还需要传递作用域,这是我们可能想要从用户那里获得的任何额外权限。在这种情况下,我们只是要获取他们的电子邮件 ID。

我们的 Facebook 登录页面是一个简单的链接到一个路由,我们在那里进行身份验证。然后用户将被带到 Facebook 进行登录和/或授权我们的网站,然后重定向回我们的fbauth路由。

在这一点上,我们只是显示返回的信息,但我们可能也想将信息保存到我们自己的数据库中。

还有更多...

如果我们在本地计算机上使用 MAMP 或 WAMP 进行测试,Facebook 允许我们使用 localhost 作为回调 URL。

使用 Twitter 凭据登录

如果我们不想担心存储用户的信息和凭据,我们可以使用 OAuth 来与另一个服务进行身份验证。一个常用的用于登录的服务是 Twitter。使用 Laravel 和 HybridAuth 库,我们可以轻松地实现与 Twitter 的 OAuth 身份验证。

准备工作

对于这个步骤,我们需要安装 HybridAuth 包,并按照使用 HybridAuth 包设置 OAuth的步骤进行设置。

如何做...

要完成这个步骤,请按照以下步骤进行:

  1. dev.twitter.com/apps创建一个新的应用程序。

  2. 获取 Consumer Key 和 Consumer Secret,并在app/config目录中创建一个名为tw_auth.php的文件:

<?php
return array(
    "base_url"   => "http://path/to/our/app/twauth/auth",
    "providers"  => array (
        "Twitter" => array (
            "enabled" => true,
            "keys"    => array ("key" => "CONSUMER_KEY",
			     "secret" => "CONSUMER_SECRET")
        )
    )
);
  1. routes.php中创建一个用于我们的 Twitter 登录按钮的路由:
Route::get('twitter', function()
{
    return "<a href='twauth'>Login with Twitter</a>";
});
  1. 创建一个路由来处理 Twitter 信息:
Route::get('twauth/{auth?}', function($auth = NULL)
{
    if ($auth == 'auth') {
        try {
            Hybrid_Endpoint::process();
        } catch (Exception $e) {
            return Redirect::to('twauth');
        }
        return;
    }

    try {
        $oauth = new Hybrid_Auth(app_path(). '/config/tw_auth.php');
        $provider = $oauth->authenticate('Twitter');
        $profile = $provider->getUserProfile();
    }
    catch(Exception $e) {
        return $e->getMessage();
    }
    echo 'Welcome ' . $profile->displayName . '<br>';
    echo 'Your image: <img src="' . $profile->photoURL. '">';
    dd($profile);
});

它是如何工作的...

获取我们的 Twitter API 凭据后,我们需要创建一个包含这些凭据和回调 URL 的配置文件。

然后我们创建一个 Twitter 登录视图,这是一个简单的链接到一个路由,我们在那里进行身份验证。然后用户将被带到 Twitter 进行登录和/或授权我们的网站,然后重定向回我们的twauth路由。在这里,我们获取他们的显示名称和他们的 Twitter 图标。

在这一点上,我们只是显示返回的信息,但我们可能也想将信息保存到我们自己的数据库中。

还有更多...

如果我们在本地计算机上使用类似 MAMP 或 WAMP 的东西进行测试,Twitter 将不允许使用 localhost 作为回调 URL,但我们可以使用127.0.0.1代替。

使用 LinkedIn 进行登录

如果我们不想担心存储用户信息和凭据,我们可以使用 OAuth 来验证另一个服务。一个常用的用于登录的服务,特别是用于商业应用程序的服务,是 LinkedIn。使用 Laravel 和HybridAuth库,我们可以轻松地实现与 LinkedIn 的 OAuth 验证。

准备工作

对于这个步骤,我们需要安装并设置 HybridAuth 包,就像在使用 HybridAuth 包设置 OAuth步骤中一样。

如何做...

要完成这个步骤,请按照以下步骤进行操作:

  1. www.linkedin.com/secure/developer创建一个新的应用程序。

  2. 获取 API 密钥和秘密密钥,在app/config目录中创建一个名为li_auth.php的文件:

<?php
return array(
    "base_url"   => "http://path/to/our/app/liauth/auth",
    "providers"  => array (
        "LinkedIn" => array (
            "enabled" => true,
            "keys"    => array ("key" => "API_KEY","secret" => "SECRET_KEY")
        )
    )
);
  1. routes.php中创建一个用于 LinkedIn 登录按钮的路由:
Route::get('linkedin', function()
{
    return "<a href='liauth'>Login with LinkedIn</a>";
});
  1. 创建一个处理 LinkedIn 信息的路由:
Route::get('liauth/{auth?}', function($auth = NULL)
{
    if ($auth == 'auth') {
        try {
            Hybrid_Endpoint::process();
        } catch (Exception $e) {
            return Redirect::to('liauth');
        }
        return;
    }

    try {
        $oauth = new Hybrid_Auth(app_path(). '/config/li_auth.php');
        $provider = $oauth->authenticate('LinkedIn');
        $profile = $provider->getUserProfile();
    }
    catch(Exception $e) {
        return $e->getMessage();
    }
    echo 'Welcome ' . $profile->firstName . ' ' . $profile->lastName . '<br>';
    echo 'Your email: ' . $profile->email . '<br>';
    echo 'Your image: <img src="' . $profile->photoURL. '">';
    dd($profile);
});

它是如何工作的...

获得我们的 LinkedIn API 凭据后,我们需要创建一个包含这些凭据和回调 URL 的配置文件。

然后我们创建一个 LinkedIn 登录视图,其中包含一个简单的链接到一个路由,我们在这个路由中进行 LinkedIn 验证。用户将被带到 LinkedIn 网站进行登录和/或授权我们的网站,然后重定向回我们的liauth路由。在这里,我们获取他们的名字、姓氏、电子邮件 ID 和他们的头像。

在这一点上,我们只是显示返回的信息,但我们可能也想将信息保存到我们自己的数据库中。

第四章:存储和使用数据

在本章中,我们将涵盖:

  • 使用迁移和模式创建数据表

  • 使用原始 SQL 语句查询

  • 使用 Fluent 查询

  • 使用 Eloquent ORM 查询

  • 在模型中使用自动验证

  • 使用高级 Eloquent 和关系

  • 创建 CRUD 系统

  • 使用 Eloquent 导入 CSV

  • 使用 RSS 作为数据源

  • 使用属性更改表列名称

  • 在 Laravel 中使用非 Eloquent ORM

介绍

任何 Web 应用程序的支柱之一是使用和操作数据。Laravel 提供了许多方便的方法来与数据库交互并显示它们的信息。在本章中,我们将从一些简单的数据库交互开始。然后,我们将使用其他非数据库作为我们的数据源,然后对我们的 Laravel 应用程序进行一些自定义。

使用迁移和模式创建数据表

使用 Laravel,我们可以轻松地使用模式和迁移创建我们的数据模型。在这个配方中,我们将看到 Laravel 如何实现这些基本功能。

准备工作

对于这个配方,我们需要一个标准的 Laravel 安装,以及在我们的数据库配置文件中配置的 MySQL 数据库。

如何做...

要完成这个配方,请按照以下步骤进行:

  1. 使用artisan从命令提示符中安装我们的迁移表:
**php artisan migrate:install**

  1. 创建一个迁移以保存我们的模式代码来创建一个新表:
**php artisan migrate:make create_shows_table**

  1. 在我们的app/database/migrations目录中,找到一个名为2012_01_01_222551_create_shows_table.php的类似文件。添加用于创建表和添加列的模式:
class CreateShowsTable extends Migration {

    /**
     * Make changes to the database.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('shows', function($table)
        {
            $table->increments('id');
            $table->string('name', 140);
            $table->integer('rating')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Revert the changes to the database.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('shows');
    }
}
  1. 运行迁移以将表添加到数据库,使用以下命令:
**php artisan migrate**

  1. 创建另一个迁移,以便我们可以向我们的表中添加一列:
**php artisan migrate:make add_actor_to_shows_table**

  1. app/database/migrations目录中,找到一个类似于2012_01_01_222551_add_actor_to_shows_table.php的文件。向我们的模式中添加列:
class AddActorToShowsTable extends Migration {

    /**
     * Make changes to the database.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('shows', function($table)
        {
            $table->string('actor')->nullable();
        });
    }

    /**
     * Revert the changes to the database.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('shows', function($table)
        {
            $table->drop_column('actor');
        });
    }
}
  1. 在命令提示符中运行迁移,以向我们的表中添加列:
**php artisan migrate**

它是如何工作的...

使用 Laravel 的 Artisan 命令行工具,运行命令来创建一个迁移表。这将跟踪我们进行的任何迁移和模式更改。然后我们使用 Artisan 创建一个将保存我们shows表模式的迁移文件。

shows模式中,我们创建一个简单的表来保存电视节目的列表以及我们对它们的评分。节目的名称设置为字符串,评分设置为整数,并且我们使用 Laravel 的默认机制来创建时间戳。当我们运行迁移时,我们的表将被创建。

如果我们决定要在表中添加另一列,我们只需使用 Artisan 创建另一个迁移文件。在这种情况下,我们将添加一个列来保存演员的姓名。我们的模式将获取我们已经创建的表,并向其添加列。当我们重新运行迁移时,数据库中的所有内容都将得到更新。

还有更多...

我们还可以使用 Artisan 的一些命令行开关为我们创建一些更多的样板代码。例如,要创建 shows 表,我们可以运行以下命令:

**php artisan migrate:make create_shows_table –table=show –create**

运行该命令将生成一个包含以下代码的迁移文件:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateShowsTable extends Migration {

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

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

}

使用原始 SQL 语句查询

Laravel 提供了许多访问数据库的方式。如果我们有以前使用过的现有查询,或者如果我们需要一些更复杂的东西,我们可以使用原始 SQL 来访问我们的数据库。

准备工作

对于这个配方,我们将使用使用迁移和模式创建数据表配方中创建的表。

如何做...

要完成这个配方,请按照以下步骤进行:

  1. 在命令提示符中,创建一个迁移,以便我们可以添加一些数据:
**php artisan migrate:make add_data_to_shows_table**

  1. 在我们的app/database/migrations目录中,找到一个类似于2012_01_01_222551_add_data_to_shows_table.php的文件,并使用原始 SQL 添加一些数据:
class AddDataToShowsTable {

    /**
     * Make changes to the database.
     *
     * @return void
     */

public function up()
    {
        $sql = 'INSERT INTO shows (name, rating, actor)
            VALUES (?, ?, ?)';
        $data1 = array('Doctor Who', '9', 'Matt Smith');
        $data2 = array('Arrested Development', '10', 'Jason
            Bateman');
        $data3 = array('Joanie Loves Chachi', '3', 'Scott
            Baio');
        DB::insert($sql, $data1);
        DB::insert($sql, $data2);
        DB::insert($sql, $data3);
    }

    /**
     * Revert the changes to the database.
     *
     * @return void
     */
    public function down()
    {
        $sql = "DELETE FROM shows WHERE name = ?";
        DB::delete($sql, array('Doctor Who'));
        DB::delete($sql, array('Arrested Development'));
        DB::delete($sql, array('Joanie Loves Chachi'));
    }
}
  1. 在命令提示符中运行迁移以添加数据:
**php artisan migrate**

  1. 在我们的app/models目录中,创建一个名为Show.php的文件,并添加一个获取节目的方法:
class Show {
    public function allShows($order_by = FALSE,$direction = 'ASC')
    {
        $sql = 'SELECT * FROM shows';
        $sql .= $order_by ? ' ORDER BY ' . $order_by. ' ' . $direction : '';
        return DB::select($sql);
    }
}
  1. 在我们的routes.php文件中,创建一个Show路由来显示模型中的信息:
Route::get('shows', function()
{
    $shows = new Show();
    $shows_by_rating = $shows->allShows('rating', 'DESC');
    dd($shows_by_rating);
}); 

它是如何工作的...

为了在我们的shows表中填充一些数据,我们首先需要使用 Artisan 命令行工具创建一个迁移。在迁移文件的up方法中,我们创建一个简单的 SQL 插入命令,并传入三个参数。然后我们创建三个数组,数组中的值与查询中的列的顺序相同。然后我们将 SQL 语句变量和值数组传递给 Laravel 的DB::insert()命令。对于我们的down方法,我们使用了一个 SQL 删除语句,通过节目名称进行搜索。一旦我们运行迁移,我们的数据将填充到表中。

接下来,我们在前端创建一个与数据库交互的模型。我们的模型有一个方法来显示表中的所有节目,还可以使用可选参数来重新排序它们的显示方式。

我们的路由实例化 Show 模型并运行allShows()方法。为了显示结果,我们使用 Laravel 的dd()辅助函数。在这一点上,我们可以将数据传递到视图中,并循环遍历以显示。

另请参阅

  • 使用迁移和模式创建数据表示例

使用 Fluent 进行查询

Laravel 提供了许多访问数据库的方式。如果我们选择不编写原始的 SQL 语句,我们可以使用 Fluent 查询构建器来简化操作。

准备工作

对于这个示例,我们将使用在使用迁移和模式创建数据表示例中创建的表。

如何做...

要完成这个示例,请按照以下步骤进行:

  1. 在命令提示符中,创建一个迁移以便我们添加一些数据:
**php artisan migrate:make add_data_to_shows_table**

  1. 在我们的app/database/migrations目录中,找到一个类似于2012_01_01_222551_add_data_to_shows_table.php的文件,并使用 Fluent 查询构建器添加一些数据:
class AddDataToShowsTable {

    /**
     * Make changes to the database.
     *
     * @return void
     */
    public function up()
    {
        $data1 = array('name' => 'Doctor Who',
            'rating' => 9, 'actor' => 'Matt Smith');
        $data2 = array('name' => 'Arrested Development',
            'rating' => 10, 'actor' => 'Jason Bateman');
        $data3 = array('name' => 'Joanie Loves Chachi',
            'rating' => 3, 'actor' => 'Scott Baio');
        DB::table('shows')->insert(array($data1, $data2,
            $data3));
    }

    /**
     * Revert the changes to the database.
     *
     * @return void
     */
    public function down()
    {
        DB::table('shows')
            ->where('name', 'Doctor Who')
            ->orWhere('name', 'Arrested Development')
            ->orWhere('name', 'Joanie Loves Chachi')
            ->delete();
    }
}
  1. 运行迁移以添加数据:
**php artisan migrate**

  1. 在我们的app/models目录中,创建一个名为Show.php的文件,并添加一个获取节目的方法:
class Show {
    public function allShows($order_by = FALSE,$direction = 'ASC')
    {
        $shows = DB::table('shows');
        return $order_by ? $shows->order_by($order_by,$direction)->get() : $shows->get();
    }
}
  1. 在我们的routes.php文件中,创建一个Show路由来显示模型中的信息:
Route::get('shows', function()
{
    $shows = new Show();
    $shows_by_rating = $shows->allShows('rating', 'DESC');
    dd($shows_by_rating);
}); 

它是如何工作的...

为了在我们的shows表中填充一些数据,我们首先需要使用 Artisan 命令行工具创建一个迁移。在迁移文件的up方法中,我们创建三个数组来保存我们的值,使用列名作为键。然后将这些数组放入一个数组中,并传递给 Fluent 的insert函数。down方法使用where()orWhere()函数来定位记录的名称,并删除它们。一旦我们运行迁移,我们的数据将填充到表中。

接下来,我们在前端创建一个与数据库交互的模型。我们的模型有一个方法来显示表中的所有节目,还可以使用可选参数来重新排序它们的显示方式。

我们的路由实例化 Show 模型并运行allShows()方法。为了显示结果,我们使用 Laravel 的dd()辅助函数。我们也可以创建一个视图,并将数据传递到那里进行循环。

还有更多...

在 Laravel 的文档中可以找到更多流畅的方法laravel.com/docs/queries

另请参阅

  • 使用迁移和模式创建数据表示例

使用 Eloquent ORM 进行查询

Laravel 提供了许多与数据库交互的方式。其中最简单的一种方式是使用 Eloquent ORM。它提供了一种简单直观的方式来处理数据。

准备工作

对于这个示例,我们将使用在使用迁移和模式创建数据表示例中创建的表。

如何做...

要完成这个示例,请按照以下步骤进行:

  1. 在命令提示符中,创建一个迁移以便我们添加一些数据:
**php artisan migrate:make add_data_to_shows_table**

  1. 在我们的app/database/migrations目录中,找到一个类似于2012_01_01_222551_add_data_to_shows_table.php的文件,并使用 Fluent 查询构建器添加一些数据:
class AddDataToShowsTable {

    /**
     * Make changes to the database.
     *
     * @return void
     */
    public function up()
    {
        $data1 = array('name' => 'Doctor Who',
            'rating' => 9, 'actor' => 'Matt Smith');
        $data2 = array('name' => 'Arrested Development',
            'rating' => 10, 'actor' => 'Jason Bateman');
        $data3 = array('name' => 'Joanie Loves Chachi',
            'rating' => 3, 'actor' => 'Scott Baio');
        DB::table('shows')->insert(array($data1, $data2,
            $data3));
    }

    /**
     * Revert the changes to the database.
     *
     * @return void
     */
    public function down()
    {
        DB::table('shows')
            ->where('name', 'Doctor Who')
            ->orWhere('name', 'Arrested Development')
            ->orWhere('name', 'Joanie Loves Chachi')
            ->delete();
    }
}
  1. 运行迁移以添加数据:
**php artisan migrate**

  1. 在我们的app/models目录中,创建一个名为Show.php的文件,它继承自Eloquent
class Show extends Eloquent{
    public function getTopShows() {
        return $this->where('rating', '>', 5)->orderBy('rating', 'DESC')->get();
    }
}
  1. 在我们的routes.php文件中,创建一个 show 路由来显示模型中的信息:
Route::get('shows', function()
{
    $shows = Show::all();
    echo '<h1>All Shows</h1>';
    foreach ($shows as $show)
    {
        echo $show->name . ' - ' . $show->rating . ' - '
		    . $show->actor . '<br>';
    }

    $show_object = new Show();
    $top_shows = $show_object->getTopShows();
    echo '<h1>Top Shows</h1>';
    foreach ($top_shows as $top_show)
    {
        echo $top_show->name . ' - ' . $top_show->rating
		     . ' - '. $top_show->actor . '<br>';
    }
});

它是如何工作的...

要在我们的shows表中填充一些数据,我们首先需要使用 Artisan 命令行工具创建一个迁移。在迁移文件的up方法中,我们创建了三个包含我们的值的数组,使用列名作为键。然后,这些数组被放入一个数组中,并传递给 Fluent 的insert函数。down方法使用where()orWhere()函数通过它们的名称来定位记录,并删除它们。一旦我们运行迁移,我们的数据将填充到表中。

接下来,我们创建一个模型来在前端与数据库交互。对于这个示例,我们只需要扩展Eloquent,ORM 将自动处理其他所有事情。我们还添加了一个方法,它将返回所有顶级节目。

我们的路由调用了 Show ORM 对象的all()方法;这将把所有数据放入$shows变量中。然后我们通过记录进行简单的循环,并显示我们想要的字段。接下来,我们通过在 Show 模型中调用方法来获取一个经过筛选的列表,只获取评分大于 5 的记录,并按评分排序。

还有更多...

在这个示例中,我们在路由中显示所有数据。理想情况下,我们会将数据传递到视图中并在那里显示。

另请参阅

  • 使用迁移和模式创建数据表示例

在模型中使用自动验证

在验证发送到数据库的数据时,理想情况下我们应该将规则和验证放在我们的模型中。在这个示例中,我们将看到一种实现这一点的方法。

准备工作

对于这个示例,我们需要一个配置了 MySQL 数据库的标准 Laravel 安装。我们还需要通过运行 Artisan 命令php artisan migrate:install来设置我们的迁移表。

如何做...

要完成这个示例,请按照以下步骤进行:

  1. 在命令提示符中,创建一个简单的users表的迁移:
**php artisan migrate:make create_users_table**

  1. 在迁移文件中创建模式。该文件位于app/database/migrations目录中,名称类似于2012_01_01_222551_create_users_table.php
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration {

    /**
     * Make changes to the database.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function($table)
        {
            $table->increments('id');
            $table->string('username', 100);
            $table->string('email', 100);
            $table->timestamps();
        });
    }

    /**
     * Revert the changes to the database.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('users');
    }
}
  1. 运行迁移:
**php artisan migrate**

  1. 在我们的app/models目录中创建一个名为User.php的文件。如果已经有一个名为User.php的文件,我们可以简单地重命名它:
<?php
class User extends Eloquent {

    protected $table = 'users';

    private $rules = array(
        'email' => 'required|email',
        'username' => 'required|min:6'
    );

    public function validate($input) {
        return Validator::make($input, $this->rules);
    }
}
  1. 创建一个加载 ORM 并尝试保存一些数据的路由:
$user = new User();
    $input = array();

    $input['email'] = 'racerx@example.com';
    $input['username'] = 'Short';
    $valid = $user->validate($input);
    if ($valid->passes()) {
        echo 'Everything is Valid!';
        // Save to the database
    } else {
        var_dump($valid->messages());
    }

它是如何工作的...

首先,我们为一个基本的users表创建一个迁移。在我们的模式中,我们设置了一个带有 ID、用户名、电子邮件 ID 和时间戳的表。然后运行迁移,在数据库中创建表。

接下来,我们设置了我们的用户模型并扩展了Eloquent。我们需要创建我们的规则,使用一个名为$rules的私有变量,其中包含我们想要检查的验证规则数组。在我们的模型中,我们创建了一个validate方法。这将通过 Laravel 的Validator运行我们的输入,使用我们刚刚设置的规则。

在我们的路由中,我们创建了一个新用户并添加了一些值。在保存之前,我们通过validate方法运行输入;如果失败,我们可以循环遍历验证错误消息。如果通过,我们可以将输入保存到我们的数据库中。

还有更多...

还有一些其他验证数据的方法。一种方法是使用一个可以为我们处理大部分验证工作的包。一个很好的包是 Ardent,可以在github.com/laravelbook/ardent找到。

使用高级 Eloquent 和关系

使用 Laravel 的 Eloquent ORM 的一个很棒的地方是,我们可以轻松地与具有外键和中间表的多个表进行交互。在这个示例中,我们将看到设置我们的模型并针对连接的表运行查询有多么容易。

准备工作

对于这个示例,我们将使用在之前的示例使用迁移和模式创建数据表在模型中使用自动验证中创建的showsusers表。

如何做...

要完成这个示例,请按照以下步骤进行:

  1. 在命令提示符中,创建一个新的中间表的迁移:
**php artisan migrate:make create_show_user**

  1. 打开app/database/migrations目录中的迁移文件,并添加模式:
use Illuminate\Database\Migrations\Migration;

class CreateShowUser extends Migration {

    /**
     * Make changes to the database.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('show_user', function($table)
        {
            $table->increments('id');
            $table->integer('user_id');
            $table->integer('show_id');
            $table->timestamps();
        });
    }

    /**
     * Revert the changes to the database.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('show_user');
    }
}
  1. 运行迁移:
**php artisan migrate**

  1. app/model目录中创建一个User.php文件:
class User extends Eloquent {
    public function shows()
    {
        return $this->belongsToMany ('Show');
    }
}
  1. 在我们的app/model目录中创建一个Show.php文件:
class Show extends Eloquent {
    public function users()
    {
        return $this->belongsToMany ('User');
    }
}
  1. routes.php中创建一个路由来添加一个新用户并附加两个节目:
Route::get('add-show', function()
{
    // Create a new User
    $user = new User();
    $user->username = 'John Doe';
    $user->email = 'johndoe@example.com';
    $user->save();

    // Attach two Shows
    $user->shows()->attach(1);
    $user->shows()->attach(3);

    foreach($user->shows()->get() as $show) {
        var_dump($show->name);
    }
});
  1. 创建一个路由来获取与一个节目关联的所有用户:
Route::get('view-show', function()
{
    $show = Show::find(1)->users;
    dd($show);
});

它是如何工作的...

我们的第一个任务是创建一个将我们的users表与我们的shows表连接的中间表。在我们的迁移模式中,我们需要为我们的user_idshow_id添加列。然后我们运行迁移,以在我们的数据库中设置表。

为了设置我们的模型,我们需要创建一个函数,该函数将返回我们的多对多关系。在我们的 User 模型中,我们创建了指向我们 Show 模型的关系的shows()函数。在 Show 模型中,我们创建了一个名为users()的函数,指向我们的 User 模型。有了这个设置,我们现在可以轻松地对两个表运行查询。

接下来,我们创建一个路由来添加一个新用户。一旦我们保存了用户,我们使用attach()方法来创建与节目的关系,并传入我们想要附加的节目的 ID。之后,如果我们查看我们的show_user表,我们会看到两条记录——一条是我们新用户的 ID 和节目 ID1,另一条是节目 ID3。通过在我们的路由中运行get()方法,我们可以循环遍历记录,并查看哪些节目名称与我们的用户关联。

我们的下一个路由将获取与一个节目关联的所有用户。在我们的情况下,我们获取 ID 为1的节目,然后获取所有用户。使用 Laravel 的dd()助手,我们可以看到我们的结果。

还有更多...

数据库关系可能变得非常复杂,这个教程只是初步介绍了一些操作。要了解更多关于 Laravel 的 Eloquent ORM 如何使用关系,请查看文档laravel.com/docs/eloquent#many-to-many

创建 CRUD 系统

为了与我们的数据库交互,我们可能需要创建一个 CRUD(创建、读取、更新和删除)系统。这样,我们可以添加和修改数据,而不需要单独的数据库客户端。这个教程将使用一个 RESTful 控制器来实现我们的 CRUD 系统。

准备工作

对于这个教程,我们将在在模型中使用自动验证的教程中创建的 User 表上进行扩展。

如何操作...

要完成这个教程,请按照以下步骤进行:

  1. app/controllers目录中,创建一个名为UsersController.php的文件,并添加以下代码:
<?php

class UsersController extends BaseController {

    public function getIndex()
    {
        $users = User::all();
        return View::make('users.index')->with('users',$users);
    }

    public function getCreate()
    {
        return View::make('users.create');
    }

    public function postCreate()
    {
        $user = new User();
        $user->username = Input::get('username');
        $user->email = Input::get('email');
        $user->save();
        return Redirect::to('users');
    }

    public function getRecord($id)
    {
        $user = User::find($id);
        return View::make('users.record')->with('user',$user);
    }

    public function putRecord()
    {
        $user = User::find(Input::get('user_id'));
        $user->username = Input::get('username');
        $user->email = Input::get('email');
        $user->save();
        return Redirect::to('users');
    }

    public function deleteRecord()
    {
        $user = User::find(Input::get('user_id'))->delete();
        return Redirect::to('users');
    }
}
  1. 在我们的routes.php文件中,添加一个指向控制器的路由:
**Route::controller('users', 'UsersController');**

  1. app/views目录中,创建一个名为users的新目录,在其中创建一个名为index.php的文件,并添加以下代码:
<style>
table, th, td {
    border:1px solid #444
}
</style>
<table>
    <thead>
        <tr>
            <th>User ID</th>
            <th>User Name</th>
            <th>Email</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        <?php foreach($users as $user): ?>
            <tr>
                <td><?php echo $user->id ?></td>
                <td><?php echo $user->username ?></td>
                <td><?php echo $user->email ?></td>
                <td>
                    <a href="users/record/<?php echo $user->id ?>">Edit</a> 
                    <form action="users/record"method="post">
                        <input type="hidden" name="_method"value="DELETE">
                        <input type="hidden" name="user_id"value="<?php echo $user->id?>">
                        <input type="submit"value="Delete">
                    </form>
                </td>
            </tr>
        <?php endforeach; ?>
    </tbody>
</table>
<a href="users/create">Add New User</a>
  1. app/views/users目录中,创建一个名为create.php的新文件,并添加以下表单:
<form action="create" method="post">
    Username:<br>
    <input name="username"><br>
    Email<br>
    <input name="email"><br>
    <input type="submit">
</form>
  1. app/views/users目录中,添加一个名为record.php的文件,并使用以下表单:
<form action="" method="post">
    <input type="hidden" name="_method" value="put">
    <input type="hidden" name="user_id" value="<?php echo$user->id ?>">
    Username:<br>
    <input name="username" value="<?php echo $user->username ?>"><br>
    Email<br>
    <input name="email" value="<?php echo $user->email?>"><br>
    <input type="submit">
</form>

它是如何工作的...

在我们的控制器中,我们的方法名称可以以我们想要使用的 HTTP 动词为前缀。然后我们在我们的路由文件中添加路由,使其指向正确的位置。

我们的第一个方法将生成所有用户的列表。我们将用户传递给我们的视图,然后循环遍历它们,并在一个简单的表中显示它们。

在该表下面,我们有一个链接到我们的第二个方法来添加一个新用户。我们的getRreate()方法显示一个简单的表单,然后该表单被发布并保存。保存后,我们将被重定向回列表页面。

要编辑一条记录,我们创建一个getRecord()方法,该方法获取传递给它的记录的 ID。我们的视图是一个表单,自动填充了传入的 ID 的用户的值。由于我们正在进行更新,我们想要使用put动词;为了实现这一点,我们需要一个隐藏字段,名称为_method,值为我们想要使用的请求。当表单提交时,Laravel 将其发送到putRecord()方法,并更新信息。

最后,要删除一条记录,我们创建一个简单的表单,其中包含隐藏字段名为_method和值为DELETE。当提交时,Laravel 将其发送到deleteRecord()方法,并将用户从数据库中删除。

还有更多...

请注意,这是最基本的 CRUD 系统。对于一个完整的系统,我们需要在每次添加或编辑数据时添加验证和错误检查。

使用 Eloquent 导入 CSV

在处理数据时,我们可能会遇到许多不同的来源和文件类型。一个常见的类型是 CSV,即逗号分隔值文件。在这个示例中,我们将获取 CSV 文件的内容并将其插入到我们的数据库中。

准备工作

要开始,我们需要一个配置了 MySQL 数据库的标准 Laravel 安装。我们还需要通过运行 Artisan 命令php artisan migrate:install来创建我们的迁移表。

如何做...

要完成这个示例,按照以下步骤操作:

  1. 在文本编辑器中创建一个名为scifi.csv的文件,将其保存到应用程序的public文件夹中。添加以下数据:
Spock,Star Trek
Kirk,Star Trek
Luke,Star Wars
Lando,Star Wars
Deckard,Blade Runner
Dave,2001
  1. 在命令提示符中创建一个迁移:
**php artisan migrate:make create_scifi_table**

  1. 打开刚刚创建的迁移文件,并添加我们的模式:
use Illuminate\Database\Migrations\Migration;

class CreateScifiTable extends Migration {

    /**
     * Make changes to the database.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('scifi', function($table)
        {
            $table->increments('id');
            $table->string('character');
            $table->string('movie');
            $table->timestamps();
        });
    }

    /**
     * Revert the changes to the database.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('scifi');
    }
}
  1. 运行迁移以创建表:
**php artisan migrate**

  1. app/models目录中创建一个名为Scifi.php的模型:
class Scifi extends Eloquent {
    protected $table = 'scifi';
}
  1. 创建一个新的路由来处理我们的 CSV 并保存结果:
Route::get('csv', function()
{
    if (($handle = fopen(public_path() .. '/scifi.csv','r')) !== FALSE)
    {
        while (($data = fgetcsv($handle, 1000, ',')) !==FALSE)
        {
                $scifi = new Scifi();
                $scifi->character = $data[0];
                $scifi->movie = $data[1];
                $scifi->save();
        }
        fclose($handle);
    }

    return Scifi::all();
});

它是如何工作的...

我们的第一步是创建一个简单的 CSV 文件,其中包含一些科幻角色的名称以及他们出现的电影。然后我们创建一个迁移和一个模式,将添加一个scifi表和我们想要保存的字段。

对于我们的模型,我们扩展Eloquent并添加一个名为$table的受保护变量,该变量设置为我们表的名称。由于我们不会为我们的表名复数化scifi,我们需要让 Eloquent 知道使用哪个表。

在我们的路由中,我们打开文件并使用 PHP 的内置函数fopen()fgetcsv()循环遍历数据。在每次循环中,我们创建一个新的Scifi对象,然后将值设置为我们从 CSV 文件中获取的数据。循环结束后,我们关闭文件。

要查看我们的数据,我们在Scifi对象上调用all()方法并返回它以显示所有数据。

使用 RSS 作为数据源

许多博客和新闻网站提供其内容的 RSS 源。使用 Laravel,我们可以获取这些源并将它们显示为一个订阅阅读器,甚至将它们保存在我们自己的数据库中。

准备工作

对于这个示例,我们只需要一个标准的 Laravel 安装和要使用的 RSS URL。

如何做...

要完成这个示例,按照以下步骤操作:

  1. 在我们的routes.php文件中创建一个新的路由来读取 RSS:
Route::get('rss', function()
{
    $source = 'http://rss.cnn.com/rss/cnn_topstories.rss';

    $headers = get_headers($source);
    $response = substr($headers[0], 9, 3);
    if ($response == '404')
    {
        return 'Invalid Source';
    }

    $data = simplexml_load_string(file_get_contents($source));

    if (count($data) == 0)
    {
        return 'No Posts';
    }
        $posts = '';
        foreach($data->channel->item as $item)
        {
            $posts .= '<h1><a href="' . $item->link . '">'. $item->title . '</a></h1>';
            $posts .= '<h4>' . $item->pubDate . '</h4>';
            $posts .= '<p>' . $item->description . '</p>';
            $posts .= '<hr><hr>';
        }
        return $posts;
});

它是如何工作的...

我们创建一个路由来保存我们的 RSS 阅读器。然后我们将我们的$source变量设置为我们想要使用的任何 RSS 源。

为了确保我们的源仍然活跃,我们使用 PHP 函数get_headers(),并获取响应代码。如果代码是404,则 URL 不起作用。

接下来,我们从 URL 获取内容,并使用simplexml_load_string()函数处理源中的 XML。如果该源实际上有数据,我们可以循环遍历它并显示信息。我们也可以在循环中将其保存到我们的数据库中。

使用属性更改表列名称

有时我们可能会使用使用不太合乎逻辑的列名创建的数据库。在这种情况下,我们可以使用 Laravel 的 Eloquent ORM 来使用更标准化的名称与表交互,而无需进行数据库更改。

准备工作

对于这个示例,我们需要一个标准的 Laravel 安装,一个正确配置的 MySQL 数据库,并且通过运行命令php artisan migrate:install设置我们的迁移表。

如何做...

要完成这个示例,按照以下步骤操作:

  1. 为我们的表创建一个名为odd的列的迁移,在命令提示符中:
**php artisan migrate:make create_odd_table --table=odd --create**

  1. 创建一个迁移以向表中添加一些数据,在命令提示符中:
**php artisan migrate:make add_data_to_odd_table**

  1. app/database/migrations文件夹中,打开create_odd_table迁移并添加模式:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateOddTable extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('odd', function(Blueprint $table)
        {
            $table->increments('MyIDcolumn');
            $table->string('MyUsernameGoesHere');
            $table->string('ThisIsAnEmail');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('odd');
    }
}
  1. app/database/migrations目录中,打开add_data_to_odd_table文件并添加一些数据:
use Illuminate\Database\Migrations\Migration;

class AddDataToOddTable extends Migration {

    /**
     * Make changes to the database.
     *
     * @return void
     */
    public function up()
    {
        $data1 = array('MyUsernameGoesHere' => 'John Doe','ThisIsAnEmail' => 'johndoe@example.com');
        $data2 = array('MyUsernameGoesHere' => 'Jane Doe','ThisIsAnEmail' => 'janedoe@example.com');
        DB::table('odd')->insert(array($data1, $data2));
    }

    /**
     * Revert the changes to the database.
     *
     * @return void
     */
    public function down()
    {
        DB::table('odd')->delete();
    }
}
  1. 在命令提示符中,运行迁移:
**php artisan migrate**

  1. app/models目录中,创建一个名为Odd.php的新文件并创建 getter:
class Odd extends Eloquent {
    protected $table = 'odd';

    public function getIdAttribute($value) {
        return $this->attributes['MyIDcolumn'];
    }

    public function getUsernameAttribute($value) {
        return $this->attributes['MyUsernameGoesHere'];
    }

    public function getEmailAttribute($value) {
        return $this->attributes['ThisIsAnEmail'];
    }
}
  1. routes.php中创建一个新的路由来访问表,使用常规的列名:
Route::get('odd', function()
{
    $odds = Odd::all();
    foreach($odds as $odd) 
    {
        echo $odd->MyIDcolumn . ' - ' . $odd->MyUsernameGoesHere . ' - ' . $odd->ThisIsAnEmail . '<br>';
    }
});
  1. 创建另一个路由,使用更标准的列名:
Route::get('notodd', function()
{
    $odds = Odd::all();
    foreach($odds as $odd) 
    {
        echo $odd->id . ' - ' . $odd->username . ' - '. $odd->email . '<br>';
    }
});

工作原理...

首先,我们创建两个迁移文件。一个文件将实际创建具有非标准列名的表,另一个将填充数据。

对于我们的模型,我们扩展Eloquent并添加一些get方法。在每个get方法内,设置我们的属性,告诉 Eloquent 我们想要使用哪个列名。现在,由于我们在模型中有getUsernameAttribute()方法,每当我们尝试在对象中访问用户名时,它实际上会访问我们定义的列名。

然后,我们创建一个路由,将从我们的odd表中提取所有记录,并循环遍历。对于我们的第一个路由,我们使用它们的真实名称访问列。在我们的第二个路由中,我们使用新的名称。如果我们访问这两个路由,我们将看到完全相同的信息。

在 Laravel 中使用非 Eloquent ORM

Laravel 的 Eloquent ORM 易于使用且非常高效。但是,有许多不同的 PHP ORM,我们可能决定我们更喜欢另一个 ORM。在这个步骤中,我们将安装 RedBean ORM 并将其用于我们的数据。

准备工作

对于这个步骤,我们将使用 RedBean ORM。您需要从www.redbeanphp.com/manual/installing下载它,并解压文件。然后将文件rb.php移动到您的应用程序的app/libraries目录中。

如何做...

要完成这个步骤,请按照以下步骤进行:

  1. composer.json文件中,使我们的自动加载器加载我们的libraries目录。autoload部分应该类似于这样:
"autoload": {
    "classmap": [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php",
        "app/libraries"
    ],
}
  1. 在命令提示符中,转储我们的自动加载器:
**php composer.phar dump-autoload**

  1. 在我们的routes.php文件中,我们将添加一个简单的配置:
$db_setup = Config::get('database.connections.mysql');
R::setup('mysql:host=' . $db_setup['host'] . ';dbname='. $db_setup['database'], $db_setup['username'],$db_setup['password']);
  1. 创建一个路由,将添加一些数据然后显示它:
Route::get('orm', function() 
{
    $superhero = R::dispense('superheroes');
    $superhero->name = 'Spiderman';
    $superhero->city = 'New York';
    $superhero->age = 24;

    $id1 = R::store($superhero);

    $superhero = R::dispense('superheroes');
    $superhero->name = 'Superman';
    $superhero->city = 'Metropolis';
    $superhero->age = 50;

    $id2 = R::store($superhero);

    $superhero = R::dispense('superheroes');
    $superhero->name = 'Batman';
    $superhero->city = 'Gotham';
    $superhero->age = 36;

    $id3 = R::store($superhero);

    $heroes = R::batch('superheroes',array($id1, $id2,$id3));

    foreach ($heroes as $hero)
    {
        echo $hero->name . ' - ' .  $hero->city . ' - '. $hero->age . '<br>';
    }
});

工作原理...

在将 RedBean 文件添加到我们的libraries目录后,我们需要更新我们的 composer 文件的自动加载器,以便它将加载rb.php文件。

设置数据库配置可以在各个地方完成,但是对于这个步骤,我们将在我们的路由文件的顶部设置它。因此,我们可以将我们的数据库信息保存在一个地方,我们使用 Laravel 的数据库配置来设置它。

完成所有这些后,我们准备在我们的应用程序中使用 RedBean。在我们的路由中,我们正在创建三个超级英雄并将它们添加到superheroes表中。使用 RedBean,如果表不存在,它将自动为您创建它并添加相关列。

最后,我们得到了三条记录,可以循环遍历它们以显示信息。

还有更多...

RedBeans 有许多功能,可能作为替代 ORM 很有用。要查看所有功能,请访问其官方手册redbeanphp.com/manual/

第五章:使用控制器和路由处理 URL 和 API

在本章中,我们将涵盖:

  • 创建一个基本控制器

  • 使用闭包创建路由

  • 创建一个 RESTful 控制器

  • 使用高级路由

  • 在路由上使用过滤器

  • 使用路由组

  • 使用路由构建 RESTful API

  • 使用命名路由

  • 在您的路由中使用子域

介绍

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

创建一个基本控制器

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

准备工作

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

如何做...

要完成这个步骤,按照以下步骤进行:

  1. app/controllers目录中,创建一个名为UsersController.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";
  }
}
  1. 然后,在routes.php文件中添加以下行:
Route::get('users', 'UsersController@actionIndex');
Route::get('users/about', 'UsersController@actionAbout');
  1. 通过访问http://your-server/usershttp://your-server/users/about来测试控制器,其中your-server是您的应用程序的 URL。

它是如何工作的...

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

回到用户控制器,在那里我们为我们的首页和关于页面定义了两个方法,每个方法都以action为前缀。对于我们的目的,我们只是返回一个字符串,但这将是我们所有控制器逻辑的地方,并且我们将设置要显示的视图。

这样,Laravel 就能解析 URL 并确定要使用哪个控制器和方法,我们需要在routes文件中注册路由。现在,在我们的浏览器中,当我们访问/users(或/users/index)时,我们将被带到我们的首页,而/users/about将带我们到我们的关于页面。

使用闭包创建路由

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

准备工作

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

如何做...

要完成这个步骤,按照以下步骤进行:

  1. app/routes.php文件中,添加以下路由:
Route::get('hello/world', function()
{
  $hello = 'Hello ';
  $world = 'World!';
  return $hello . $world;
});
  1. 打开浏览器,通过访问http://your-server/hello/world来测试路由,其中your-server是您的应用程序的 URL。

它是如何工作的...

Laravel 中的路由被认为是 RESTful 的,这意味着它们响应不同的 HTTP 动词。大多数时候,当简单地查看网页时,我们使用GET动词,如Route::get。我们的第一个参数是我们用于路由的 URL,它可以是几乎任何有效的 URL 字符串。在我们的情况下,当用户转到hello/world时,它将使用这个路由。之后是我们的闭包,或匿名函数。

在闭包中,我们可以从我们的模型中提取任何数据,进行我们想要的任何逻辑,并调用我们想要使用的视图。在我们的示例中,我们只是设置了一些变量并返回它们连接的值。

创建一个 RESTful 控制器

也许有一天我们想要拥有一个 RESTful 的 Web 应用程序,比如构建一个 API。为了实现这一点,我们需要我们的路由响应各种 HTTP 请求。闭包的路由已经以这种方式设置,但在这个示例中,我们将保持 MVC 模式,并创建一个 RESTful 的控制器。

准备工作

对于这个示例,我们需要一个标准的 Laravel 安装和创建一个基本控制器示例中的代码。

如何做...

要完成这个步骤,按照以下步骤进行:

  1. 在用户控制器中,用以下代码替换代码:
<?php
class  UsersController extends BaseController {

  public function getIndex()
  {
    $my_form = "<form method='post'>
                      <input name='text' value='Testing'>
                      <input type='submit'>
                      </form>";
    return $my_form;

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

  public function getAbout()
  {
     return "This is a User About page";
  }
}
  1. routes.php中,添加到我们的控制器的路由:
Route::controller('users', 'UsersController');
  1. 在浏览器中,转到http://your-server/users(其中your-server是您的 Web 服务器的 URL),然后单击提交按钮。

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

它是如何工作的...

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

我们的getIndex()方法是当我们转到/users时的默认方法,因为大多数页面视图都是GET请求。在这个例子中,我们返回一个非常简单的表单,该表单将把输入提交回自身。然而,由于表单使用了POST请求,它将触发postIndex()方法,这就是表单可以被处理的地方。在我们的示例中,我们只是使用 Laravel 的dd()助手来显示提交的表单输入。

使用高级路由

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

准备工作

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

操作步骤…

要完成这个示例,请按照以下步骤操作:

  1. 在我们的routes.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 <strong>' . $show . '</strong>';
  }

  return 'You picked the show <strong>' . $show .'</strong> from the year <em>' . $year . '</em>.';
})
->where('year', '\d{4}');
  1. 打开浏览器,并通过在地址栏中输入http://your-server/tvshow/MASH/1981(其中your-server是您服务器的 URL)来测试路由。

它是如何工作的...

我们首先让我们的路由响应GET请求的tvshow。如果我们想要向路由传递参数,我们需要设置通配符。只要我们将相同的名称传递给函数,我们可以使用任意多个参数并且可以随意命名它们。对于这个示例,我们想要获取一个节目标题,并且为了使这个参数可选,我们在末尾添加了问号。

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

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

在路由上使用过滤器

Laravel 的一个强大功能是添加过滤器,可以在请求发送到我们的应用程序之前和之后运行。在这个示例中,我们将探讨这些过滤器。

准备工作

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

操作步骤...

要完成这个示例,请按照以下步骤操作:

  1. 在我们的routes.php文件中,添加一个只有管理员可以访问的路由,并附加过滤器:
Route::get('admin-only', array('before' => 'checkAdmin', 'after' => 'logAdmin', function() 
{
  return 'Hello there, admin!';
}));
  1. 在我们的filters.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'));
});
  1. 创建一个可以设置管理员会话的路由:
Route::get('set-admin', function()
{
  Session::put('user_type', 'admin');
  return Redirect::to('admin-only');
});
  1. 通过转到http://your-server/admin-only(其中your-server是您服务器的 URL)来测试路由,并注意结果。然后,转到set-admin并查看这些结果。

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

它是如何工作的...

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

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

在访问路由之后,我们创建一个访问的日志以及访问路由的日期。

在这一点上,如果我们在浏览器中去到admin-onlybefore过滤器会启动并显示错误消息。然后,如果我们去到我们的日志目录并查看日志,它会显示尝试的时间、日志消息的名称和响应。对于我们来说,它会显示You are not an Admin. Go Away!

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

还有更多...

这是一个非常基本的身份验证方法,只是为了展示过滤器的有用性。对于更好的身份验证,使用 Laravel 内置的方法。

使用路由组

在创建 Web 应用程序时,我们可能会发现一些需要相同 URL 前缀或过滤器的路由。使用 Laravel 的路由组,我们可以轻松地将它们应用到多个路由。

准备工作

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

操作方法…

要完成这个示例,请按照以下步骤进行:

  1. 在我们的app/filters.php文件中,创建一个检查用户的过滤器:
Route::filter('checkUser', function()
{
  if ('user' !== Session::get('profile'))
  {
    return 'You are not Logged In. Go Away!';
  }
});
  1. app/routes.php文件中,创建一个可以设置我们的个人资料会话的路由:
Route::get('set-profile', function()
{
  Session::set('profile', 'user');
  return Redirect::to('profile/user');
});
  1. routes.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';
    });
});
  1. 在我们的浏览器中,然后我们去到http://path/to/our/server/profile/user,我们会得到一个错误。如果我们然后去到http://path/to/our/server/set-profile,它会重定向我们并显示正确的页面。

它是如何工作的...

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

在我们的路由中,然后创建一个将为我们设置profile会话然后重定向我们到路由组的路由。通常在登录后会设置会话,但这里我们只是测试以确保它有效。

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

使用路由构建 RESTful API

现代 Web 应用程序的一个常见需求是拥有一个第三方可以运行查询的 API。由于 Laravel 是以 RESTful 模式为重点构建的,因此很容易用很少的工作来构建一个完整的 API。

准备工作

对于这个示例,我们需要一个标准的 Laravel 安装,并且正确配置了 MySQL 数据库,与我们的应用程序连接起来。

操作方法…

要完成这个示例,请按照以下步骤进行:

  1. 打开命令行,转到 Laravel 安装的根目录,并使用以下命令为我们的表创建一个迁移:
php artisan migrate:make create_shows_table
  1. app/database/migrations目录中,找到类似2012_12_01_222821_create_shows_table.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');
  }
}
  1. 回到命令行,按照以下方式运行迁移:
php artisan migrate
  1. 创建另一个迁移以添加一些测试数据:
php artisan migrate:make add_shows_data
  1. app/database/migrations文件夹中,打开add_shows_data文件,并添加以下查询:
<?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();
  }
}
  1. 在命令行中,按照以下方式运行迁移:
php artisan migrate
  1. app/models目录中,创建一个名为Show.php的文件,并添加以下代码:
<?php
class Show extends Eloquent {
  protected $table = 'shows';
}
  1. routes.php中,创建一个返回所有 show 或单个 show 的 JSON 的路由:
Route::get('show/{id?}', function($id = null)
{
  if (!$id)
  {
    return Show::all();
  }
  if ($show = Show::find($id))
  {
    return $show;
  }
});
  1. 创建一个将添加新 show 的路由如下:
Route::post('show', function()
{
  $show = new Show;
  $show->name = Input::get('name');
  $show->year = Input::get('year');
  $show->save();
  return $show;
});
  1. 创建一个将删除记录的路由:
Route::delete('show/{id}', function($id)
{
  if ($show = Show::find($id))
  {
    $show->delete();
    return json_encode(array('message' => 'Record ' . $id. ' deleted.'));
  }
});
  1. 创建一个更新记录的路由:
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;
 }
});
  1. 创建一个路由来保存我们的添加和编辑show form
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);
});
  1. 创建一个路由来显示一个列表,以便我们可以删除一个 show:
Route::get('show-delete', function()
{
  $shows = Show::all();
  return View::make('show-delete')->with('shows',$shows);
});
  1. 在我们的app/views文件夹中,创建一个名为show-form.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() ?>
  1. 然后,在app/views中,创建一个名为show-delete.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; ?>
  1. 通过浏览器访问show-formshow-delete路由来测试它。

工作原理...

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

对于我们的路由,我们将响应四种不同的 HTTP 动词,GETPOSTPUTDELETE,但都在同一个 URL,show上。GET请求将有两个目的。首先,如果 URL 中没有传入 ID,它将显示来自数据库的整个列表。其次,如果有 ID,它将显示单个记录。通过直接返回 eloquent 对象,它将自动将我们的对象显示为 JSON。

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

然后,我们添加一个响应DELETE请求的路由。它获取id参数,删除记录,并显示 JSON 以确认删除成功。

最后,我们有一个响应PUT请求和id参数的路由。该路由将加载传入 ID 的记录,然后编辑值。如果更新正确,它会显示更新后的记录的 JSON。

要展示 API 的运行情况,我们需要创建一个表单来添加和更新记录。我们的show-form路由检查是否传入了 ID,如果是,则使用PUT方法创建一个表单,并将记录的值加载到字段中。如果没有设置 ID,我们将使用POST方法创建一个空白表单。

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

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

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

要发布到 API,请使用以下代码行:

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

还有更多...

请记住,这个 API 示例非常基础。要使其更好,我们需要在添加或更新记录时添加一些验证。还可以考虑添加某种身份验证,以便公众无法更改我们的表格和删除记录。

我们还可以使用 Laravel 的资源控制器来实现类似的功能。有关更多信息,请参阅文档laravel.com/docs/controllers#resource-controllers

使用命名路由

有时我们需要更改路由的名称。在一个大型网站上,如果我们有多个链接指向错误的路由,这可能会引起很多问题。Laravel 提供了一种简单易用的方式来为我们的路由分配名称,这样我们就不必担心它们是否会更改。

准备工作

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

如何做...

要完成这个示例,请按照以下步骤操作:

  1. 在我们的routes.php文件中,创建一个命名路由如下:
Route::get('main-route', array('as' => 'named', function()
{
  return 'Welcome to ' . URL::current();
}));
  1. 创建一个执行简单重定向到命名路由的路由:
Route::get('redirect', function()
{
  return Redirect::route('named');
});
  1. 创建一个显示链接到命名路由的路由:
Route::get('link', function()
{
  return '<a href="' . URL::route('named') . '">Link!</a>';
});
  1. 在浏览器中,访问http://your-server/redirecthttp://your-server/link(其中your-server是服务器的 URL),注意它们将我们发送到main-route路由。

  2. 现在,将main-route路由重命名为new-route

Route::get('new-route', array('as' => 'named', function()
{
  return 'Welcome to ' . URL::current();
}));
  1. 在浏览器中,访问redirectlink路由,看看它们现在将我们发送到哪里。

工作原理...

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

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

在您的路由中使用子域

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

准备就绪

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

如何做...

要完成这个配方,请按照以下步骤操作:

  1. 在我们域名的 DNS 中,我们需要添加一个"A"记录,使用通配符为子域,例如*.example.com,然后将其指向我们服务器的 IP 地址。

  2. 打开 Apache 的httpd.conf文件,并添加一个虚拟主机,如下所示:

<VirtualHost *:80>
  ServerName example.com
  ServerAlias *.example.com
</VirtualHost>
  1. 在命令行中,转到我们的应用程序路由并为我们的names表创建一个迁移:
php artisan migrate:make create_names_table
  1. migrations目录中,打开create_names_table文件并添加我们的模式:
<?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');
  }
}
  1. 回到命令行,创建另一个迁移以添加一些测试数据:
php artisan migrate:make add_names_data
  1. migrations目录中打开add_names_data文件:
<?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();
  }
}
  1. 在命令行中,运行迁移如下:
php artisan migrate
  1. 创建一个路由,根据子域从names表中获取信息:
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);
});
  1. 在浏览器中,访问我们的域名,使用相关子域,例如http://ted.example.com

它是如何工作的...

首先,我们需要更新我们的 DNS 和我们的服务器。在我们的 DNS 中,我们创建一个通配符子域,并在我们的 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);

    });
});

第六章:显示您的视图

在本章中,我们将涵盖:

  • 创建和使用基本视图

  • 将数据传递到视图

  • 将视图加载到另一个视图/嵌套视图中

  • 添加资产

  • 使用 Blade 创建视图

  • 使用 TWIG 模板

  • 利用高级 Blade 用法

  • 创建内容的本地化

  • 在 Laravel 中创建菜单

  • 与 Bootstrap 集成

  • 使用命名视图和视图组件

介绍

在 Model-View-Controller 设置中,我们的视图保存所有的 HTML 和样式,以便我们可以显示我们的数据。在 Laravel 中,我们的视图可以使用常规的 PHP 文件,也可以使用 Laravel 的 Blade 模板。Laravel 还可以扩展到允许我们使用任何我们想要包含的模板引擎。

创建和使用基本视图

在这个步骤中,我们将看到一些基本的视图功能,以及我们如何在我们的应用程序中包含视图。

准备工作

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

如何做...

按照以下步骤完成这个步骤:

  1. app/views目录中,创建一个名为myviews的文件夹。

  2. 在新的myviews目录中,创建两个文件:home.phpsecond.php

  3. 打开home.php并在 HTML 中添加以下代码:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Home Page</title>
    </head>
    <body>
      <h1>Welcome to the Home page!</h1>
      <p>
        <a href="second">Go to Second Page</a>
      </p>
    </body>
</html>
  1. 打开second.php文件并在 HTML 中添加以下代码:
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Second Page</title>
    </head>
    <body>
      <h1>Welcome to the Second Page</h1>
      <p>
        <a href="home">Go to Home Page</a>
      </p>
    </body>
</html>
  1. 在我们的app/routes.php文件中,添加将返回这些视图的路由:
Route::get('home', function()
{
  return View::make('myviews.home');
});
Route::get('second', function()
{
  return View::make('myviews.second');
});
  1. 通过转到http://{your-server}/home(其中your-server是我们的 URL)并单击链接来测试视图。

它是如何工作的...

Laravel 中的所有视图都保存在app/views目录中。我们首先创建两个文件,用于保存我们的 HTML。在这个例子中,我们正在创建静态页面,每个视图都包含自己的完整 HTML 标记。

在我们的路由文件中,然后返回View::make(),并传入视图的名称。由于我们的视图在视图目录的子目录中,我们使用点表示法。

将数据传递到视图

在我们的 Web 应用程序中,我们通常需要显示来自数据库或其他数据存储的某种数据。在 Laravel 中,我们可以轻松地将这些数据传递到我们的视图中。

准备工作

对于这个步骤,我们需要完成创建和使用基本视图步骤。

如何做...

要完成这个步骤,请按照以下步骤进行:

  1. 打开routes.php并将我们的主页和第二个路由替换为包含以下数据:
Route::get('home', function()
{
  $page_title = 'My Home Page Title';
  return View::make('myviews.home')->with('title',$page_title);
});
Route::get('second', function()
{
  $view = View::make('myviews.second');
  $view->my_name = 'John Doe';
  $view->my_city = 'Austin';
  return $view;
});
  1. view/myviews目录中,打开home.php并用以下代码替换代码:
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Home Page : <?= $title ?></title>
    </head>
    <body>
        <h1>Welcome to the Home page!</h1>
        <h2><?= $title ?></h2>
      <p>
        <a href="second">Go to Second Page</a>
      </p>
    </body>
</html>
  1. views/myviews目录中,打开second.php文件,并用以下代码替换代码:
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Second Page</title>
    </head>
    <body>
      <h1>Welcome to the Second Page</h1>
        <p> You are <?= $my_name ?>, from <?= $my_city ?>
        </p>
      <p>
        <a href="home">Go to Home Page</a>
      </p>
    </body>
</html>
  1. 通过转到http://{your-server}/home(其中your-server是我们的 URL)来测试视图,然后单击链接。

它是如何工作的...

如果我们想要将数据传递到我们的视图中,Laravel 提供了各种方法来实现这一点。我们首先通过将单个变量传递给视图来更新我们的第一个路由,通过将with()方法链接到View::make()。然后,在视图文件中,我们可以通过使用我们选择的任何名称来访问变量。

在我们的下一个路由中,我们将View::make()分配给一个变量,然后将值分配为对象的属性。然后我们可以在视图中将这些属性作为变量访问。要显示视图,我们只需返回对象变量。

还有更多...

向视图添加数据的另一种方法类似于我们第二个路由中的方法;但是我们使用数组而不是对象。因此,我们的代码看起来类似于以下内容:

$view = View::make('myviews.second');
$view['my_name'] = 'John Doe';
$view['my_city'] = 'Austin';
return $view;

将视图加载到另一个视图/嵌套视图中

我们的网页往往会有类似的布局和 HTML 结构。为了帮助分离重复的 HTML,我们可以在 Laravel 中使用嵌套视图

准备工作

对于这个步骤,我们需要完成创建和使用基本视图步骤。

如何做...

要完成这个步骤,请按照以下步骤进行:

  1. app/view目录中,添加一个名为common的新文件夹。

  2. common目录中,创建一个名为header.php的文件,并将以下代码添加到其中:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>My Website</title>
    </head>
    <body>
  1. common目录中,创建一个名为footer.php的文件,并将以下代码添加到其中:
<footer>&copy; 2013 MyCompany</footer>  
  </body>
</html>
  1. common目录中,创建一个名为userinfo.php的文件,并添加以下代码:
<p>You are <?= $my_name ?>, from <?= $my_city ?></p>
  1. routes.php文件中,更新主页和第二个路由,包括以下嵌套视图:
Route::get('home', function()
{
  return View::make('myviews.home')
      ->nest('header', 'common.header')
      ->nest('footer', 'common.footer');
});
Route::get('second', function()
{
  $view = View::make('myviews.second');
  $view->nest('header', 'common.header')->nest('footer','common.footer');
  $view->nest('userinfo', 'common.userinfo', array('my_name' => 'John Doe', 'my_city' => 'Austin'));
  return $view;
});
  1. views/myviews目录中,打开home.php文件,并添加以下代码:
<?= $header ?>
    <h1>Welcome to the Home page!</h1>
    <p>
      <a href="second">Go to Second Page</a>
    </p>
<?= $footer ?>
  1. views/myviews目录中,打开second.php文件,并添加以下代码:
<?= $header ?>
<h1>Welcome to the Second Page</h1>
  <?= $userinfo ?>
<p>
    <a href="home">Go to Home Page</a>
</p>
<?= $footer ?>
  1. 通过转到http://{your-server}/home(其中your-server是我们的 URL),然后点击链接来测试视图。

它是如何工作的...

首先,我们需要将头部和页脚代码从我们的视图中分离出来。由于这些将在每个页面上都是相同的,我们在我们的views文件夹中创建一个子目录来保存我们的公共文件。第一个文件是我们的页眉,它将包含直到<body>标签的所有内容。第二个文件是我们的页脚,它将包含页面底部的 HTML。

我们的第三个文件是一个userinfo视图。如果我们有用户帐户和个人资料,我们经常希望在侧边栏或页眉中包含用户的数据。为了保持视图的一部分单独,我们创建了userinfo视图,并传递了一些数据给它。

对于我们的主页路由,我们将使用我们的主页视图,并嵌套头部和页脚。nest()方法中的第一个参数是我们将在主视图中使用的名称,第二个参数是视图的位置。在这个例子中,我们的视图在 common 子目录中,所以我们使用点表示法来引用它们。

在我们的主页视图中,为了显示嵌套视图,我们打印出了我们在路由中使用的变量名。

对于我们的第二个路由,我们嵌套了头部和页脚,但我们还想添加userinfo视图。为此,我们向nest()方法传入了第三个参数,这是我们要发送到视图的数据数组。然后,在我们的主视图中,当我们打印出userinfo视图时,它将自动包含这些变量。

另请参阅

  • 将数据传递到视图的方法

添加资产

动态网站几乎需要使用 CSS 和 JavaScript。使用 Laravel 资产包提供了一种简单的方法来管理这些资产并将它们包含在我们的视图中。

准备工作

对于这个方法,我们需要使用加载视图到另一个视图/嵌套视图方法中创建的代码。

如何做到这一点...

要完成这个方法,按照以下步骤进行:

  1. 打开composer.json文件,并将asset包添加到require部分,使其看起来类似于以下内容:
"require": {
      "laravel/framework": "4.0.*",
      "teepluss/asset": "dev-master"
  },
  1. 在命令行中,运行 composer update 来下载包,如下所示:
**php composer.phar update**

  1. 打开app/config/app.php文件,并在提供者数组的末尾添加ServiceProvider,如下所示:
'Teepluss\Asset\AssetServiceProvider',
  1. 在相同的文件中,在aliases数组中,添加包的别名,如下所示:
'Asset' => 'Teepluss\Asset\Facades\Asset'
  1. app/filters.php文件中,添加一个自定义过滤器来处理我们的资产,如下所示:
Route::filter('assets', function()
{
  Asset::add('jqueryui', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js', 'jquery');
  Asset::add('jquery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js');
  Asset::add('bootstrap', 'http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css');
});

Update the home and second routes to use the filter
Route::get('home', array('before' => 'assets', function()
{
  return View::make('myviews.home')
      ->nest('header', 'common.header')
      ->nest('footer', 'common.footer');
}));
Route::get('second', array('before' => 'assets', function()
{
  $view = View::make('myviews.second');
  $view->nest('header', 'common.header')->nest('footer', 'common.footer');
  $view->nest('userinfo', 'common.userinfo', array('my_name' => 'John Doe', 'my_city' => 'Austin'));
  return $view;
}));
  1. views/common目录中,打开header.php文件,并按照以下代码使用:
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>My Website</title>
        <?= Asset::styles() ?>
    </head>
    <body>
  1. views/common目录中,打开footer.php文件,并使用以下代码:
<footer>&copy; 2013 MyCompany</footer> 
<?= Asset::scripts() ?>
  </body>
</html>
  1. 通过转到http://{your-server}/home(其中your-server是我们的 URL),点击链接并查看页面源代码来测试视图,以查看包含的资产。

它是如何工作的...

asset包使向我们的 HTML 添加 CSS 和 JavaScript 文件变得非常容易。首先,我们需要在路由中“注册”每个资产。为了使事情变得更简单一些,我们将在一个在路由之前调用的过滤器中添加这些资产。这样,我们只需在一个地方编写代码,而且更改也会很容易。为了我们的目的,我们将使用来自 CDN 源的 jQuery、jQueryUI 和 bootstrap CSS。

add()方法的第一个参数是我们给资产的名称。第二个参数是资产的 URL;它可以是相对路径或完整的 URL。第三个可选参数是资产的依赖关系。在我们的例子中,jQueryUI 要求 jQuery 已经被加载,所以我们在第三个参数中传入了我们的 jQuery 资产的名称。

然后我们更新我们的路由以添加过滤器。如果我们在我们的过滤器中添加或删除任何资产,它将自动反映在我们的每个路由中。

由于我们使用了嵌套视图,我们只需要将资产添加到我们的页眉和页脚视图中。我们的 CSS 文件是通过styles()方法调用的,JavaScript 是通过scripts()方法调用的。Laravel 检查资产的文件扩展名,并自动将它们放在正确的位置。如果我们查看源代码,我们会注意到 Laravel 还确保在 jQueryUI 之前添加了 jQuery 脚本,因为我们将其设置为依赖项。

另请参阅

  • 第五章中的在路由上使用过滤器食谱,使用控制器和路由处理 URL 和 API

使用 Blade 创建视图

PHP 有许多可用的模板库,Laravel 的 Blade 是其中之一。这个食谱将展示一个易于扩展的方法来使用 Blade 模板,并快速上手。

准备工作

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

如何做...

要完成这个食谱,请按照以下步骤进行:

  1. routes.php文件中,创建新的路由,如下所示:
Route::get('blade-home', function()
{
  return View::make('blade.home');
});
Route::get('blade-second', function()
{
  return View::make('blade.second');
});
  1. views目录中,创建一个名为layout的新文件夹。

  2. views/layout目录中,创建一个名为index.blade.php的文件,并将以下代码添加到其中:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>My Site</title>
    </head>
    <body>
    <h1>
    @section('page_title')
      Welcome to 
    @show
    </h1>
    @yield('content')
    </body>
</html>
  1. views目录中,创建一个名为blade的文件夹。

  2. views/blade目录中,创建一个名为home.blade.php的文件,并将以下代码添加到其中:

@extends('layout.index')

@section('page_title')
  @parent
    Our Blade Home
@endsection

@section('content')
  <p>
    Go to {{ HTML::link('blade-second', 'the Second Page.') }}
  </p>
@endsection
  1. views/blade目录中,创建一个名为second.blade.php的文件,并将以下代码添加到其中:
@extends('layout.index')

@section('page_title')
  @parent
    Our Second Blade Page
@endsection

@section('content')
  <p>
    Go to {{ HTML::link('blade-home', 'the Home Page.')}}
  </p>
@endsection
  1. 通过转到http://{your-server}/blade-home(其中your-server是我们的 URL),然后单击链接,查看页面源代码,以查看包含的 Blade 布局。

它是如何工作的...

首先,我们创建两个简单的路由,它们将返回我们的 Blade 视图。通过使用点表示法,我们可以看到我们将把文件放在我们的views文件夹的blade子目录中。

我们的下一步是创建一个 Blade 布局视图。这将是我们页面的骨架,并将放在我们的views文件夹的布局子目录中,文件扩展名必须是blade.php。这个视图是简单的 HTML,有两个例外:@section()@yield()区域。这些内容是我们的视图中将被替换或添加的内容。

在我们的路由视图中,我们首先声明要使用哪个 Blade 布局文件,对于我们的情况是@extends('layout.index')。然后我们可以添加和修改我们在布局中声明的内容部分。对于page_title部分,我们想要显示布局中的文本,但我们想要在末尾添加一些额外的文本。为了实现这一点,我们在内容区域的第一件事就是调用@parent,然后放入我们自己的内容。

@section('content')中,布局中没有默认文本,所以一切都将被添加。使用 Blade,我们还可以使用{{ }}大括号来打印出我们需要的任何 PHP。在我们的情况下,我们使用 Laravel 的HTML::link()来显示一个链接。现在,当我们转到页面时,所有的内容区域都被放在了布局的正确位置。

使用 TWIG 模板

Laravel 的 Blade 模板可能很好,但有时我们需要另一个 PHP 模板库。一个流行的选择是 Twig。这个食谱将展示如何将 Twig 模板整合到我们的 Laravel 应用程序中。

准备工作

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

如何做…

按照以下步骤完成这个食谱:

  1. 打开composer.json文件,并在require部分添加以下行:
"rcrowe/twigbridge": "0.4.*"
  1. 在命令行中,更新 composer 以安装包:
**php composer.phar update**

  1. 打开app/config/app.php文件,并在providers数组中添加 Twig ServiceProvider,如下所示:
'TwigBridge\TwigServiceProvider'
  1. 在命令行中,运行以下命令来创建我们的配置文件:
**php artisan config:publish rcrowe/twigbridge**

  1. routes.php中,创建一个路由如下:
Route::get('twigview', function()
{
  $link = HTML::link('http://laravel.com', 'the Laravel site.');
  return View::make('twig')->with('link', $link);
**});**

  1. views目录中,创建一个名为twiglayout.twig的文件,并将以下代码添加到其中:
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>My Site</title>
    </head>
    <body>
    <h1>
        {% block page_title %}
            Welcome to
        {% endblock %}
    </h1>
    {% block content %}{% endblock %}
    </body>
</html>
  1. views目录中,创建一个名为twig.twig的文件,并将以下代码添加到其中:
{% extends "twiglayout.twig" %}

{% block page_title %}
	{{ parent() }}
	My Twig Page
{% endblock %}

{% block content %}
    <p>
		Go to {{ link|raw }}
	</p>
{% endblock %}
  1. 通过转到http://your-server/twigview(其中your-server是我们的 URL)来测试视图,并查看页面源代码以查看包含的 twig 布局。

工作原理...

首先,我们将在我们的应用程序中安装TwigBranch包。该包还安装了Twig库。安装包后,我们使用artisan创建其配置文件,并添加其服务提供程序。

在我们的路由中,我们将使用与 Laravel 内置视图库相同的语法,并调用视图。我们还创建了一个简单的链接,将其保存到一个变量中,并将该变量传递到视图中。

接下来,我们创建我们的布局。所有 Twig 视图文件都必须具有.twig扩展名,因此我们的布局命名为twiglayout.twig。布局中包含一个标准的 HTML 框架,但我们添加了两个 Twig 内容块。page_title块具有一些默认内容,而content块为空。

对于我们路由的视图,我们首先通过扩展布局视图来开始。对于我们的page_title块,我们首先通过使用{{ parent()}}打印出默认内容,然后添加我们自己的内容。然后添加我们的内容块,并显示我们作为变量传递的链接。使用 Twig,我们不需要为我们的变量使用$,如果我们传入 HTML,Twig 会自动转义它。因此在我们的视图中,由于我们想要显示链接,我们需要确保添加原始参数。

现在,如果我们在浏览器中打开我们的页面,我们将看到所有内容都在正确的位置上。

利用高级的 Blade 用法

使用 Laravel 的 Blade 模板系统,我们可以访问一些强大的功能,使我们的开发速度更快。对于这个示例,我们将向我们的 blade 视图传递一些数据,并循环遍历它,以及一些条件语句。

准备工作

对于这个示例,我们将需要在使用 Blade 创建视图示例中创建的代码。

如何做...

按照以下步骤完成这个示例:

  1. 打开routes.php文件,并按以下方式更新blade-homeblade-second路由:
Route::get('blade-home', function()
{
  $movies = array(
    array('name' => 'Star Wars', 'year' => '1977', 'slug'=> 'star-wars'),
    array('name' => 'The Matrix', 'year' => '1999', 'slug' => 'matrix'),
    array('name' => 'Die Hard', 'year' => '1988', 'slug'=> 'die-hard'),
    array('name' => 'Clerks', 'year' => '1994', 'slug' => 'clerks')
  );
  return View::make('blade.home')->with('movies', $movies);
});
Route::get('blade-second/(:any)', function($slug)
{
  $movies = array(
    'star-wars' => array('name' => 'Star Wars', 'year' => '1977', 'genre' => 'Sci-Fi'),
    'matrix' => array('name' => 'The Matrix', 'year' => '1999', 'genre' => 'Sci-Fi'),
    'die-hard' => array('name' => 'Die Hard', 'year' => '1988', 'genre' => 'Action'),
    'clerks' => array('name' => 'Clerks', 'year' => '1994', 'genre' => 'Comedy')
  );
  return View::make('blade.second')->with('movie', $movies[$slug]);
});
  1. views/blade目录中,使用以下代码更新home.blade.php文件:
@extends('layout.index')

@section('page_title')
  @parent
    Our List of Movies
@endsection

@section('content')
  <ul>
    @foreach ($movies as $movie)
      <li>{{ HTML::link('blade-second/' . $movie['slug'],$movie['name']) }} ( {{ $movie['year'] }} )</li>
          @if ($movie['name'] == 'Die Hard')
                 <ul>
                   <li>Main character: John McClane</li>
                 </ul>
          @endif
    @endforeach
  </ul>
@endsection
  1. views/blade目录中,使用以下代码更新second.blade.php文件:
@extends('layout.index')

@section('page_title')
  @parent
     Our {{ $movie['name'] }} Page
@endsection

@section('content')
  @include('blade.info')
  <p>
    Go to {{ HTML::link('blade-home', 'the Home Page.') }}
  </p>
@endsection
  1. views/blade目录中,创建一个名为info.blade.php的新文件,并将以下代码添加到其中:
<h1>{{ $movie['name'] }}</h1>
<p>Year: {{ $movie['year'] }}</p>
<p>Genre: {{ $movie['genre'] }}</p>
  1. 通过转到http://{your-server}/blade-home(其中your-server是我们的 URL)来测试视图,并单击链接以查看视图的工作。

工作原理...

对于这个示例,我们将向我们的 Blade 视图传递一些数据,循环遍历它,并添加一些条件语句。通常,我们会将其与数据库中的结果一起使用,但是为了我们的目的,我们将在我们的路由中创建一个简单的数据数组。

我们的第一个路由包含一个电影数组,其中包含它们的年份和我们可以用于 URL 的 slug。我们的第二个路由将创建一个包含 slug 作为键并接受 URL 中的 slug 的数组。然后,通过调用具有 slug 作为键的电影,我们将电影的详细信息传递到视图中。

在我们的第一个视图中,我们创建了一个@foreach循环,以遍历数组中的所有数据。我们还包含了一个简单的@if语句,用于检查特定的电影,然后打印出一些额外的信息。当我们循环遍历时,我们显示链接到第二个路由,并添加 slug。

第二个视图显示电影的名称,但是还通过在内容块中使用@include()包含另一个 Blade 视图。这样,所有数据也可以在包含的视图中使用;因此,对于我们的info视图,我们可以直接使用我们在路由中设置的相同变量。

创建内容的本地化

如果我们的应用程序将被不同国家或说不同语言的人使用,我们需要对内容进行本地化。Laravel 提供了一种简单的方法来实现这一点。

准备工作

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

如何做...

对于这个教程,请按照以下步骤进行:

  1. app/lang目录中,添加三个新目录(如果尚未存在):enesde

  2. en目录中,创建一个名为localized.php的文件,并添加以下代码:

<?php

return array(
  'greeting' => 'Good morning :name',
  'meetyou' => 'Nice to meet you!',
  'goodbye' => 'Goodbye, see you tomorrow.',
);
  1. es目录中,创建一个名为localized.php的文件,并添加以下代码:
<?php

return array(
  'greeting' => 'Buenos días :name',
  'meetyou' => 'Mucho gusto!',
  'goodbye' => 'Adiós, hasta mañana.',
);
  1. de目录中,创建一个名为localized.php的文件,并添加以下代码:
<?php

return array(
  'greeting' => 'Guten morgen :name',
  'meetyou' => 'Es freut mich!',
  'goodbye' => 'Tag. Bis bald.',
);
  1. 在我们的routes.php文件中,创建四个路由如下:
Route::get('choose', function()
{
  return View::make('language.choose');
});
Route::post('choose', function()
{
  Session::put('lang', Input::get('language'));
  return Redirect::to('localized');
});
Route::get('localized', function()
{
  $lang = Session::get('lang', function() { return 'en';});
  App::setLocale($lang);
  return View::make('language.localized');
});
Route::get('localized-german', function()
{
  App::setLocale('de');
  return View::make('language.localized-german');
});
  1. views目录中,创建一个名为language的文件夹。

  2. views/language中,创建名为choose.php的文件,并添加以下代码:

<h2>Choose a Language:</h2>
<?= Form::open() ?>
<?= Form::select('language', array('en' => 'English', 'es' => 'Spanish')) ?>
<?= Form::submit() ?>
<?= Form::close() ?>
  1. views/language目录中,创建一个名为localized.php的文件,并添加以下代码:
<h2>
  <?= Lang::get('localized.greeting', array('name' => 'Lindsay Weir')) ?>
</h2>
<p>
  <?= Lang::get('localized.meetyou') ?>
</p>
<p>
  <?= Lang::get('localized.goodbye') ?>
</p>
<p>
  <?= HTML::link('localized-german', 'Page 2') ?>
</p>
  1. views/language目录中,创建一个名为localized-german.php的文件,并添加以下代码:
<h2>
  <?= Lang::get('localized.greeting', array('name' =>'Lindsay Weir')) ?>
</h2>
<p>
  <?= Lang::get('localized.meetyou') ?>
</p>
<p>
  <?= Lang::get('localized.goodbye') ?>
</p>
  1. 在浏览器中,转到http://{your-server}/choose(其中your-server是我们的 URL),提交表单,并测试本地化。

它是如何工作的...

对于这个教程,我们首先在app/lang目录中设置我们的语言目录。我们将使用en作为英语文件,es作为西班牙语文件,de作为德语文件。在每个目录中,我们创建一个使用完全相同名称的文件,并添加一个数组,使用完全相同的键。

我们的第一个路由将是一个语言选择器页面。在此页面上,我们可以选择英语或西班牙语。当我们提交时,它将POST到路由,创建一个新会话,添加选择,并重定向到页面以显示所选语言的文本。

我们的本地化路由获取会话并将选择传递给App::setLocale()。如果没有设置会话,我们还有一个默认值为英语。

在我们的本地化视图中,我们使用Lang::get()打印出文本。在我们的语言文件的第一行中,我们还包含了:name占位符,因此当我们调用语言文件时,我们可以传递一个包含占位符名称的数组作为键。

我们的最后一个路由显示了我们如何在路由中静态设置语言默认值。

在 Laravel 中创建菜单

菜单是大多数网站的常见组成部分。在这个教程中,我们将使用 Laravel 的嵌套视图创建菜单,并根据我们所在的页面更改菜单项的默认“状态”。

准备工作

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

如何做...

我们需要按照以下步骤完成这个教程:

  1. routes.php文件中,创建三个路由如下:
Route::get('menu-one', function()
{
  return View::make('menu-layout')
      ->nest('menu', 'menu-menu')
      ->nest('content', 'menu-one');
});
Route::get('menu-two', function()
{
  return View::make('menu-layout')
      ->nest('menu', 'menu-menu')
      ->nest('content', 'menu-two');
});
Route::get('menu-three', function()
{
  return View::make('menu-layout')
      ->nest('menu', 'menu-menu')
      ->nest('content', 'menu-three');
});
  1. 在视图目录中,创建一个名为menu-layout.php的文件,并添加以下代码:
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Menu Example</title>
        <style>
            #container {
              width: 1024px; 
              margin: 0 auto; 
              border-left: 2px solid #ddd;
              border-right: 2px solid #ddd;
              padding: 20px;
            }
            #menu { padding: 0 }
            #menu li {
               display: inline-block;
               border: 1px solid #ddf;
               border-radius: 6px;
               margin-right: 12px;
               padding: 4px 12px;
            }
            #menu li a {
               text-decoration: none;
               color: #069;
            }
            #menu li a:hover { text-decoration: underline}
            #menu li.active { background: #069 }
            #menu li.active a { color: #fff }
        </style>
    </head>
    <body>
      <div id="container">
          <?= $menu ?>
          <?= $content ?>
      </div>
    </body>
</html>
  1. views目录中,创建一个名为menu-menu.php的文件,并添加以下代码:
<ul id="menu">
  <li class="<?= Request::segment(1) == 'menu-one' ?'active' : '' ?>">
    <?= HTML::link('menu-one', 'Page One') ?>
  </li>
  <li class="<?= Request::segment(1) == 'menu-two' ? 'active' : '' ?>">
      <?= HTML::link('menu-two', 'Page Two') ?>
  </li>
  <li class="<?= Request::segment(1) == 'menu-three' ?'active' : '' ?>">
      <?= HTML::link('menu-three', 'Page Three') ?>
  </li>
</ul>
  1. views目录中,创建三个视图文件,分别命名为menu-one.phpmenu-two.phpmenu-three.php

  2. 对于menu-one.php,使用以下代码:

<h2>Page One</h2>
<p>
  Lorem ipsum dolor sit amet.
</p>
  1. 对于menu-two.php,使用以下代码:
<h2>Page Two</h2>
<p>
  Suspendisse eu porta turpis
</p>
  1. 对于menu-three.php,使用以下代码:
<h2>Page Three</h2>
<p>
  Nullam varius ultrices varius.
</p>
  1. 在浏览器中,转到http://{your-server}/menu-one(其中your-server是我们的 URL),并通过菜单链接进行点击。

它是如何工作的...

我们首先创建三个路由来保存我们的三个页面。每个路由将使用单个布局视图,并嵌入一个特定于路由的菜单视图和内容视图。

我们的布局视图是一个基本的 HTML 骨架,带有一些页面 CSS。由于我们想要突出显示当前页面的菜单项,一个类选择器被命名为active,并将添加到我们的菜单列表项中。

接下来,我们创建我们的菜单视图。我们使用无序列表,其中包含到每个页面的链接。为了在当前页面项目中添加active类,我们使用 Laravel 的Request::segment(1)来获取我们所在的路由。如果它与列表项相同,我们添加active类,否则留空。然后我们使用 Laravel 的HTML::link()来添加链接到我们的页面。

其他三个视图只是非常简单的内容,有一个标题和几个单词。现在,当我们在浏览器中查看页面时,我们会看到我们所在页面的菜单项被突出显示,而其他页面没有。如果我们单击链接,那个项目将被突出显示,其他项目将不会被突出显示。

与 Bootstrap 集成

Bootstrap CSS 框架最近变得非常流行。这个示例将展示我们如何在 Laravel 中使用这个框架。

准备工作

对于这个示例,我们需要一个标准的 Laravel 安装。我们还需要安装assets包,就像添加资产示例中演示的那样。可选地,我们可以下载 Bootstrap 文件并将其保存在本地。

如何做...

要完成这个示例,请按照以下步骤进行:

  1. routes.php文件中,创建一个新的路由,如下所示:
Route::any('boot', function()
{
  Asset::add('jquery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js');
  Asset::add('bootstrap-js', 'http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js', 'jquery');
  Asset::add('bootstrap-css', 'http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css');
  $superheroes = array('Batman', 'Superman', 'Wolverine','Deadpool', 'Iron Man');
  return View::make('boot')->with('superheroes',$superheroes);
});
  1. views目录中,创建一个名为boot.php的文件,并向其中添加以下代码:
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>My Bootstrap Page</title>
    <?= Asset::styles() ?>
  </head>
  <body>
    <div class="container">
      <h1>Using Bootstrap with Laravel</h1>
      <ul class="nav nav-tabs">
        <li class="active"><a href="#welcome" data-toggle="tab">Welcome</a></li>
        <li><a href="#about" data-toggle="tab">About Us</a></li>
        <li><a href="#contact" data-toggle="tab">Contact</a></li>
      </ul>
        <div class="tab-content">
          <div class="tab-pane active" id="welcome">
            <h4>Welcome to our site</h4>
            <p>Here's a list of Superheroes:</p>
            <ul>
              <?php foreach($superheroes as $hero): ?>
                <li class="badge badge-info"><?= $hero ?></li>
              <?php endforeach; ?>
            </ul>
        </div>
          <div class="tab-pane" id="about">
            <h4>About Us</h4>
              <p>Cras at dui eros. Ut imperdiet pellentesque mi faucibus dapibus.Phasellus vitae lacus at massa viverra condimentum quis quis augue. Etiam pharetra erat id sem pretium egestas. Suspendisse mollis, dolor a sagittis hendrerit, urna velit commodo dui, id adipiscing magna magna ac ligula. Nunc in ligula nunc.</p>
          </div>
          <div class="tab-pane" id="contact">
            <h3>Contact Form</h3>
              <?= Form::open('boot', 'POST') ?>
                <?= Form::label('name', 'Your Name') ?>
                <?= Form::text('name') ?>
                <?= Form::label('email', 'Your Email') ?>
                <?= Form::text('email') ?>
                <br>
                <?= Form::button('Send', array('class' =>'btn btn-primary')) ?>

                <?= Form::close() ?>
          </div>
       </div>
    </div>
    <?= Asset::scripts() ?>
  </body>
</html>
  1. 在浏览器中,转到http://your-server/boot(其中your-server是我们的 URL),并单击选项卡。

它是如何工作的...

对于这个示例,我们将创建一个单一的路由,并使用 Bootstrap 选项卡切换内容。为了使我们的路由响应任何请求,我们使用Route::any()并传入我们的闭包。要添加 CSS 和 JavaScript,我们可以使用一个过滤器,就像添加资产示例中的过滤器一样;然而,对于一个单一的路由,我们将把它包含在闭包中。因此,我们不必下载它们,我们将只使用 Bootstrap 和 jQuery 的 CDN 版本。

接下来,在我们的路由中,我们需要一些数据。这将是绑定数据库的好地方,但是出于我们的目的,我们将使用一个简单的数组,其中包含一些超级英雄的名字。然后将该数组传递到我们的视图中。

我们从一个 HTML 骨架开始查看,并在头部包含我们的样式,在关闭</body>标签之前包含脚本。在页面顶部,我们使用 Bootstrap 的导航样式和数据属性来创建我们的选项卡链接。然后在我们的正文中,我们使用三个不同的选项卡窗格,其 ID 对应于我们菜单中的<a href>标签。

当我们查看页面时,我们会看到第一个窗格显示,其他所有内容都被隐藏。通过单击其他选项卡,我们可以切换显示哪个选项卡窗格。

另请参阅

  • 添加资产示例

使用命名视图和视图组件

这个示例将展示如何使用 Laravel 的命名视图和视图组件来简化一些我们路由代码。

准备工作

对于这个示例,我们将使用在 Laravel 中创建菜单示例中创建的代码。我们还需要在添加资产示例中安装assets包。

如何做...

要完成这个示例,请按照以下步骤进行:

  1. routes.php文件中,添加一个名为view的文件,并向其中添加以下代码:
View::name('menu-layout', 'layout');
  1. routes.php中,添加一个视图组件,如下所示:
View::composer('menu-layout', function($view)
{
  Asset::add('bootstrap-css', 'http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css');
    $view->nest('menu', 'menu-menu');
    $view->with('page_title', 'View Composer Title');
});
  1. routes.php中,更新菜单路由如下:
Route::get('menu-one', function()
{
  return View::of('layout')->nest('content', 'menu-one');
});
Route::get('menu-two', function()
{
  return View::of('layout')->nest('content', 'menu-two');
});
Route::get('menu-three', function()
{
  return View::of('layout')->nest('content', 'menu-three');
});
  1. views目录中,使用以下代码更新menu-layout.php文件:
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title><?= $page_title ?></title>
        <?= Asset::styles() ?>
        <style>
          #container {
            width: 1024px; 
            margin: 0 auto; 
            border-left: 2px solid #ddd;
            border-right: 2px solid #ddd;
            padding: 20px;
          }
          #menu { padding: 0 }
          #menu li {
            display: inline-block;
            border: 1px solid #ddf;
            border-radius: 6px;
            margin-right: 12px;
            padding: 4px 12px;
          }
          #menu li a {
            text-decoration: none;
            color: #069;
          }
          #menu li a:hover { text-decoration: underline }
          #menu li.active { background: #069 }
          #menu li.active a { color: #fff }
        </style>
    </head>
    <body>
      <div id="container">
        <?= $menu ?>
        <?= $content ?>
      </div>
    </body>
</html>
  1. 在浏览器中,转到http://{your-server}/menu-one(其中your-server是我们的 URL),并单击菜单链接。

它是如何工作的...

我们通过为我们的视图创建一个名称来开始这个示例。如果我们的视图文件名或目录结构很长或复杂,这将允许我们在我们的路由中创建一个简单的别名。这也将允许我们在将来更改我们的视图文件名;此外,如果我们在多个地方使用它,我们只需要更改一行。

接下来,我们创建一个视图组件。当您创建视图时,组件中的任何代码都将自动调用。在我们的示例中,每次创建视图时,我们都包含三个内容:包含 Bootstrap CSS 文件的资产,一个嵌套视图和一个传递给视图的变量。

对于我们的三个路由,我们将使用我们创建的名称,调用View::of('layout'),并将其嵌套在我们的内容中,而不是View::make('menu-layout')。由于我们的布局视图有一个 composer,它将自动嵌套我们的菜单,添加 CSS,并传递页面标题。

另请参阅

  • 在 Laravel 中创建菜单示例

第七章:创建和使用 Composer 包

在本章中,我们将涵盖:

  • 下载和安装包

  • 使用生成器包设置应用程序

  • 在 Laravel 中创建 Composer 包

  • 将您的 Composer 包添加到 Packagist

  • 将非 Packagist 包添加到 Composer

  • 创建自定义 artisan 命令

介绍

Laravel 中的一个很棒的功能是我们可以轻松地使用包含其他人使用 bundles 制作的类库。在 Laravel 网站上,已经有许多有用的 bundles,其中一些自动化某些任务,而其他一些则可以轻松地与第三方 API 集成。

PHP 世界的最新补充是 Composer,它允许我们使用不特定于 Laravel 的库(或包)。

在本章中,我们将开始使用 bundles,并创建自己的 bundle 供其他人下载。我们还将看到如何将 Composer 整合到我们的 Laravel 安装中,以打开我们可以在应用程序中使用的各种 PHP 库。

下载和安装包

Laravel 最好的功能之一是它的模块化。大部分框架都是使用经过充分测试并在其他项目中广泛使用的库或构建的。通过使用 Composer 进行依赖管理,我们可以轻松地包含其他包并将它们无缝地整合到我们的 Laravel 应用程序中。

对于这个配方,我们将在我们的应用程序中安装两个流行的包:Jeffrey Way 的 Laravel 4 生成器和Imagine图像处理包。

准备工作

对于这个配方,我们需要使用 Composer 进行 Laravel 的标准安装。

如何操作...

对于这个配方,我们将按照以下步骤进行:

  1. 转到packagist.org/

  2. 在搜索框中,搜索way generator,如下截图所示:如何操作...

  3. 点击way/generators的链接:如何操作...

  4. packagist.org/packages/way/generators查看详细信息,并注意获取包版本的require行。对于我们的目的,我们将使用"way/generators": "1.0.*"

  5. 在我们应用程序的根目录中,打开composer.json文件,并在require部分中添加包,使其看起来像这样:

"require": {
       "laravel/framework": "4.0.*",
       "way/generators": "1.0.*"
},
  1. 返回到packagist.org,并按照以下截图中显示的方式搜索imagine如何操作...

  2. 点击imagine/imagine的链接,并复制dev-master的 require 代码:如何操作...

  3. 返回到我们的composer.json文件,并更新require部分以包括imagine包。现在它应该类似于以下代码:

"require": {
      "laravel/framework": "4.0.*",
      "way/generators": "1.0.*",
      "imagine/imagine": "dev-master"
},
  1. 打开命令行,在我们应用程序的根目录中,运行 Composer update 如下:
php composer.phar update
  1. 最后,我们将添加生成器服务提供者,因此打开app/config/app.php文件,并在 providers 数组中添加以下行:
'Way\Generators\GeneratorsServiceProvider'

它是如何工作的...

要获取我们的包,我们首先转到packagist.org,并搜索我们想要的包。我们也可以点击浏览包链接。它将显示最近的包列表以及最受欢迎的包。点击我们想要的包后,我们将被带到详细页面,其中列出了各种链接,包括包的存储库和主页。我们还可以点击包的维护者链接,查看他们发布的其他包。

在下面,我们将看到包的各种版本。如果我们打开该版本的详细页面,我们将找到我们需要在composer.json文件中使用的代码。我们可以选择使用严格的版本号,为版本添加通配符,或者使用dev-master,这将安装包的主分支上更新的任何内容。对于Generators包,我们只会使用 1.0 版本,但允许对该版本进行任何次要修复。对于imagine包,我们将使用dev-master,因此无论版本号如何,都将下载其存储库的主分支中的内容。

然后我们在 Composer 上运行更新,它将自动下载并安装我们选择的所有包。最后,要在我们的应用程序中使用Generators,我们需要在应用程序的配置文件中注册服务提供者。

使用 Generators 包设置应用程序

Generators是一个流行的 Laravel 包,可以自动化相当多的文件创建。除了controllersmodels之外,它还可以通过命令行界面生成viewsmigrationsseeds等等。

准备工作

对于这个示例,我们将使用由Jeffrey Way维护的 Laravel 4 Generators 包,该包在下载和安装包示例中安装。我们还需要一个正确配置的 MySQL 数据库。

操作步骤…

按照这个示例的步骤:

  1. 在我们应用程序的根目录中打开命令行,并使用生成器按如下方式为我们的城市创建一个脚手架:
**php artisan generate:scaffold cities --fields="city:string"**

  1. 在命令行中,按如下方式为我们的超级英雄创建一个脚手架:
**php artisan generate:scaffold superheroes --fields="name:string, city_id:integer:unsigned"**

  1. 在我们的项目中,查看app/database/seeds目录,并找到名为CitiesTableSeeder.php的文件。打开它,并按如下方式向$cities数组中添加一些数据:
<?php

class CitiesTableSeeder extends Seeder {

  public function run()
  {
    DB::table('cities')->delete();

    $cities = array(
         array(
                'id'         => 1,
                'city'       => 'New York',
                'created_at' => date('Y-m-d g:i:s',time())
              ),
         array(
                'id'         => 2,
                'city'       => 'Metropolis',
                'created_at' => date('Y-m-d g:i:s',time())
              ),
         array(
                'id'         => 3,
                'city'       => 'Gotham',
                'created_at' => date('Y-m-d g:i:s',time())
              )
    );

    DB::table('cities')->insert($cities);
  }
}
  1. app/database/seeds目录中,打开SuperheroesTableSeeder.php并向其中添加一些数据:
<?php

class SuperheroesTableSeeder extends Seeder {

  public function run()
  {
    DB::table('superheroes')->delete();

      $superheroes = array(
           array(
                 'name'       => 'Spiderman',
                 'city_id'    => 1,
                 'created_at' => date('Y-m-d g:i:s', time())
                 ),
           array(
                 'name'       => 'Superman',
                 'city_id'    => 2,
                 'created_at' => date('Y-m-d g:i:s', time())
                 ),
           array(
                 'name'       => 'Batman',
                 'city_id'    => 3,
                 'created_at' => date('Y-m-d g:i:s', time())
                 ),
           array(
                 'name'       => 'The Thing',
                 'city_id'    => 1,
                 'created_at' => date('Y-m-d g:i:s', time())
                 )
      );

    DB::table('superheroes')->insert($superheroes);
  }
}
  1. 在命令行中,运行迁移,然后按如下方式对数据库进行种子处理:
php artisan migrate
**php artisan db:seed**

  1. 打开一个网页浏览器,转到http://{your-server}/cities。我们将看到我们的数据如下截图所示:操作步骤…

  2. 现在,导航到http://{your-server}/superheroes,我们将看到我们的数据如下截图所示:操作步骤…

工作原理…

我们首先运行城市和超级英雄表的脚手架生成器。使用--fields标签,我们可以确定我们想要在表中的列,并设置数据类型等选项。对于我们的城市表,我们只需要城市的名称。对于我们的超级英雄表,我们希望得到英雄的名称以及他们居住的城市的 ID。

当我们运行生成器时,许多文件将自动为我们创建。例如,对于城市,我们将在我们的 models 中得到City.php,在 controllers 中得到CitiesController.php,在我们的 views 中得到一个cities目录,其中包括索引、显示、创建和编辑视图。然后我们得到一个名为Create_cities_table.php的迁移,一个CitiesTableSeeder.php种子文件,以及我们的tests目录中的CitiesTest.php。我们还将有我们的DatabaseSeeder.php文件和我们的routes.php文件更新以包含我们需要的一切。

为了向我们的表中添加一些数据,我们打开了CitiesTableSeeder.php文件,并更新了我们的$cities数组,其中包含我们想要添加的每一行的数组。我们对SuperheroesTableSeeder.php文件也做了同样的事情。最后,我们运行迁移和种子处理,我们的数据库将被创建,并且所有数据将被插入。

Generators包已经创建了我们需要操纵数据的视图和控制器,因此我们可以轻松地转到我们的浏览器并查看所有数据。我们还可以创建新行,更新现有行和删除行。

在 Laravel 中创建一个 Composer 包

使用 Laravel 的工作台,我们可以轻松创建一个可以由 Composer 使用和安装的包。我们还可以添加功能,使该包无缝集成到我们的 Laravel 应用程序中。在这个示例中,我们将创建一个简单的包,用于显示指定用户的 Vimeo 视频列表。

准备工作

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

如何做…

要完成这个示例,请按照以下步骤进行:

  1. app/config目录中,打开workbench.php文件并使用以下信息进行更新:
<?php

return array(

    'name' => 'Terry Matula',

    'email' => 'terrymatula@gmail.com',

);
  1. 在命令行中,使用 artisan 来设置我们的包:
**php artisan workbench matula/vimeolist --resources**

  1. 找到将保存我们源文件的目录,并创建一个名为Vimeolist.php的文件。在这个示例中,我们将文件放在workbench/matula/vimeolist/src/Matula/Vimeolist/中:
<?php namespace Matula\Vimeolist;

class Vimeolist
{
  private $base_url = 'http://vimeo.com/api/v2/{username}/videos.json';
  private $username;

  public function __construct($username = 'userscape') {
      $this->setUser($username);
      return $this;
  }

  /**
   * Set the username for our list
   *
   * @return void
   */
  public function setUser($username = NULL) {
      $this->username = is_null($username) ? $this->username : urlencode($username);
       return $this;
  }

  /**
   * Set up the url and get the contents
   *
   * @return json
   */
  private function getFeed() {
      $url  = str_replace('{username}', $this->username,$this->base_url);
      $feed = file_get_contents($url);
      return $feed;
  }

  /**
   * Turn the feed into an object
   *
   * @return object
   */
  public function parseFeed() {
       $json = $this->getFeed();
       $object = json_decode($json);
       return $object;
  }

  /**
   * Get the list and format the return
   *
   * @return array
   */
  public function getList() {
       $list = array();
       $posts = $this->parseFeed();
       foreach ($posts as $post) {
             $list[$post->id]['title']    = $post->title;
             $list[$post->id]['url']    = $post->url;
             $list[$post->id]['description'] = $post->description;
             $list[$post->id]['thumbnail'] = $post->thumbnail_small;
       }
       return $list;
  }
}
  1. 在刚刚创建的文件所在的目录中,打开名为VimeolistServiceProvider.php的文件并更新它:
<?php namespace Matula\Vimeolist;

use Illuminate\Support\ServiceProvider;

class VimeolistServiceProvider extends ServiceProvider {

  /**
   * Indicates if loading of the provider is deferred.
   *
   * @var bool
   */
  protected $defer = false;

  /**
   * Bootstrap the application events.
   *
   * @return void
   */
  public function boot()
  {
        $this->package('matula/vimeolist');
  }

  /**
   * Register the service provider.
   *
   * @return void
   */
  public function register()
  {
      $this->app['vimeolist'] = $this->app->share(function($app)
            {
             return new Vimeolist;
            });
  }

  /**
   * Get the services provided by the provider.
   *
   * @return array
   */
  public function provides()
  {
    return array('vimeolist');
  }
}
  1. app/config目录中的app.php文件中,在providers数组中,添加我们的服务提供程序如下:
'Matula\Vimeolist\VimeolistServiceProvider',
  1. 在命令行中,运行以下命令:
**php composer.phar dump-autoload**

  1. routes.php中,添加一个显示数据的路由如下:
Route::get('vimeo/{username?}', function($username = null) use ($app)
{
  $vimeo = $app['vimeolist'];
  if ($username) {
      $vimeo->setUser($username);
  }
  dd($vimeo->getList());
});

它是如何工作的…

我们的第一步是更新我们工作台的配置文件,以保存我们的姓名和电子邮件地址。然后,这将用于我们在 Laravel 中创建的任何其他包。

接下来,我们运行 artisan 命令来创建我们包所需的文件。通过使用--resources标志,它还将生成其他文件和目录,可以专门用于 Laravel。完成后,我们的工作台目录中将有一个包含所有包文件的新文件夹。在深入目录之后,我们将进入一个包含我们服务提供程序文件的目录,在这个目录中,我们将添加我们的类文件。

这个示例类将简单地从 Vimeo API 中获取用户的视频列表。我们有一些方法可以允许我们设置用户名,获取 API 端点的内容,将 JSON 转换为 PHP 对象,然后创建并返回一个格式化的数组。作为最佳实践,我们还应该确保我们的代码经过测试,并且我们可以将这些文件放在test目录中。

为了更好地与 Laravel 集成,我们需要更新服务提供程序。我们首先更新register方法并设置要传递给 Laravel 的app变量的名称,然后我们更新provides方法以返回包名称。接下来,我们需要更新我们的应用程序配置文件以实际注册服务提供程序。然后,一旦我们在 Composer 中运行dump-autoload命令,我们的新包将可供使用。

最后,我们创建一个与包交互的路由。我们将有一个可选参数,即用户名。我们还需要确保我们的路由中有$app变量。然后,当我们调用$app['vimeolist']时,服务提供程序将自动实例化我们的类,并允许我们访问 Vimeo 列表。对于我们的目的,我们只使用 Laravel 的dd()辅助函数来显示数据,但我们也可以将其传递给视图并使其看起来更好。

还有更多…

Laravel 还可以选择为我们的包创建一个门面,因此我们可以使用类似$vimeo = Vimeolist::setUser()的方式进行调用。还有许多其他可以在laravel.com/docs/packages文档中找到的包选项。

将您的 Composer 包添加到 Packagist

为了更容易地分发我们的包,我们应该将它们提交到网站packagist.org。在这个示例中,我们将看到如何在 GitHub 上设置我们的包并将其添加到 Packagist。

准备工作

对于这个示例,我们需要完成Laravel 中创建 Composer 包示例,并且我们还需要一个活跃的 GitHub 帐户。

如何做…

要完成这个示例,请按照以下步骤进行:

  1. 在命令行中,移动到workbench/matula/vimeolist目录并设置我们的git仓库如下:
git init
git add -A
git commit –m 'First Package commit'
  1. github.com/new创建一个新的 GitHub 存储库,并将其命名为vimeolist

  2. 将我们的包添加到 GitHub:

git remote add origin git@github.com:{username}/vimeolist.git
**git push –u origin master**

  1. 前往packagist.org/login/并使用您的 GitHub 帐户登录。

  2. 单击以下截图中显示的绿色提交包按钮:如何做...

  3. 存储库 URL文本字段中,添加 GitHub 的只读 Git URL,如下截图所示:如何做...

  4. 单击检查,如果一切正常,单击提交

它是如何工作的...

我们首先在包的主目录中创建一个git存储库。然后我们在 GitHub 中为我们的文件创建一个存储库,将该远程存储库添加到我们的本地存储库,然后将我们的本地存储库推送到 GitHub。

在 Packagist 网站上,我们使用我们的 GitHub 帐户登录,并允许packagist.org访问。然后,我们使用来自我们存储库的 GitHub URL 在packagist.org/packages/submit提交我们的包。单击检查后,Packagist 将查看代码并将其格式化以供 Composer 使用。如果有任何错误,我们将收到提示需要做什么来修复它们。

如果一切正常,并且我们单击提交,我们的包将被列在 Packagist 网站上。

另请参阅

  • 在 Laravel 中创建一个 Composer 包教程

向 Composer 添加一个非 Packagist 包

向我们的composer.json文件添加一行,并让 Composer 自动下载和安装一个包非常好,但它要求该包在packagist.org上可用。在这个教程中,我们将看到如何安装在 Packagist 上不可用的包。

准备工作

对于这个教程,我们将需要一个标准的 Laravel 安装。

如何做...

要完成这个教程,请按照以下步骤操作:

  1. 在 GitHub 上,我们需要找到一个我们想要使用的包。在这个例子中,我们将使用在github.com/wesleytodd/Universal-Forms-PHP找到的UniversalForms包。

  2. 打开我们的主composer.json文件,并按以下方式更新require部分:

"require": {
       "laravel/framework": "4.0.*",
       "wesleytodd/universal-forms": "dev-master"
  },
  1. composer.json中,在require部分下,添加我们要使用的存储库:
"repositories": [
     {
         "type": "vcs",
         "url": "https://github.com/wesleytodd/Universal-Forms-PHP"
     }
  ],
  1. 在命令行中,按以下方式更新 Composer:
**php composer.phar update**

  1. 打开app/config/app.php文件,并使用以下行更新providers数组:
'Wesleytodd\UniversalForms\Drivers\Laravel\UniversalFormsServiceProvider',
  1. routes.php中,实例化该类,并在我们的路由上使用它,如下所示:
$form_json = '{
       "action" : "uform",
       "method" : "POST",
       "fields" : [
             {
               "name" : "name",
               "type" : "text",
               "label" : "Name",
               "rules" : ["required"]
             },
             {
               "name" : "email",
               "type" : "email",
               "label" : "Email",
               "value" : "myemail@example.com",
               "rules" : ["required", "email"]
              },
              {
                "name" : "message",
                "type" : "textarea",
                "label" : "Message",
                "rules" : ["required", "length[30,0]"]
              }
       ]
}';

$uform = new Wesleytodd\UniversalForms\Drivers\Laravel\Form($form_json);

Route::get('uform', function() use ($uform)
{
  return $uform->render();
});

Route::post('uform', function() use ($uform)
{
  // validate
  $valid = $uform->valid(Input::all());
  if ($valid) {
       // Could also save to database
       dd(Input::all());
  } else {
       // Could redirect back to form
       dd($uform->getErrors());
  }
});

它是如何工作的...

我们的第一步是像其他 Composer 包一样添加所需包的行。但是,由于这个包在packagist.org上不可用,如果我们尝试更新 Composer,它将抛出错误。为了使其工作,我们需要添加一个 Composer 要使用的存储库。Composer 有许多不同的选项可用于使用其他存储库,它们可以在getcomposer.org/doc/05-repositories.md#vcs找到。

接下来,我们更新 Composer,它将为我们安装包。由于这个包带有一个 Laravel 服务提供者,我们然后更新我们的配置文件以注册它。

现在我们可以在我们的应用程序中使用该包。对于我们的目的,我们将在路由之外实例化该类,并将其传递到路由的闭包中。然后我们可以像平常一样使用该库。这个特定的包将接受一个 JSON 字符串或文件,并自动为我们创建表单输出。

创建自定义 artisan 命令

Laravel 的 artisan 命令行工具使许多任务变得容易完成。如果我们想要创建自己的任务并使用 artisan 来运行它们,这个过程非常简单。在这个教程中,我们将看到如何创建一个 artisan 任务,自动在我们的views目录中创建一个 HTML5 骨架。

准备工作

对于这个教程,我们将需要一个标准的 Laravel 安装。

如何做...

要完成这个教程,请按照以下步骤操作:

  1. 在命令行中,运行artisan命令来创建我们需要的文件:
**php artisan command:make SkeletonCommand**

  1. app/commands目录中,打开SkeletonCommand.php文件并按以下方式更新代码:
<?php

use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Illuminate\Filesystem\Filesystem as File;

class SkeletonCommand extends Command {

  /**
   * The console command name.
   *
   * @var string
   */
  protected $name = 'skeleton:make';

  /**
   * The console command description.
   *
   * @var string
   */
  protected $description = 'Creates an HTML5 skeleton view.';

   /**
     * File system instance
     *
     * @var File
     */
    protected $file;

  /**
   * Create a new command instance.
   *
   * @return void
   */
  public function __construct()
  {
    parent::__construct();
    $this->file = new File();
  }

  /**
   * Execute the console command.
   *
   * @return void
   */
  public function fire()
  {
        $view = $this->argument('view');
        $file_name = 'app/views/' . $view;
        $ext = ($this->option('blade')) ? '.blade.php' :'.php';
            $template = '<!DOCTYPE html>
            <html>
            <head>
               <meta charset=utf-8 />
               <title></title>
               <link rel="stylesheet" type="text/css"media="screen" href="css/style.css" />
                <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js">
                </script>
                  <!--[if IE]>
                        <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
                  <![endif]-->
            </head>
            <body>
            </body>
            </html>';

            if (!$this->file->exists($file_name)) {
               $this->info('HTML5 skeleton created!');
               return $this->file->put($file_name . $ext,$template) !== false;
        } else {
             $this->info('HTML5 skeleton created!');
             return $this->file->put($file_name . '-' .time() . $ext, $template) !== false;
        }

    $this->error('There was a problem creating yourHTML5 skeleton');
       return false;
  }

  /**
   * Get the console command arguments.
   *
   * @return array
   */
  protected function getArguments()
  {
      return array(
           array('view', InputArgument::REQUIRED, 'The name of the view.'),
      );
  }

  /**
   * Get the console command options.
   *
   * @return array
   */
  protected function getOptions()
  {
     return array(
     array('blade', null, InputOption::VALUE_OPTIONAL, 'Use Blade templating?', false),
     );
  }

} 
  1. app/start目录中,打开artisan.php文件并添加以下行:
Artisan::add(new SkeletonCommand);
  1. 在命令行中,测试新命令:
**php artisan skeleton:make MyNewView --blade=true**

它是如何工作的...

我们的第一步是使用 artisan 的command:make函数,并传入我们想要使用的命令的名称。运行后,我们会在app/commands目录中找到一个与我们选择的名称相同的新文件。

在我们的SkeletonCommand文件中,我们首先添加一个名称。这将是 artisan 要响应的命令。接下来,我们设置一个描述,当我们列出所有 artisan 命令时将显示。

对于这个命令,我们将访问文件系统,因此我们需要确保添加 Laravel 的Filesystem类,并在我们的构造函数中实例化它。然后,我们来到fire()方法。这是我们想要运行的所有代码的地方。为了我们的目的,我们使用一个单一参数来确定我们的view文件名将是什么,如果--blade参数设置为true,我们将把它变成一个blade文件。然后,我们创建一个包含我们的 HTML5 骨架的字符串,尽管我们也可以将其制作成一个单独的文件并引入文本。

然后使用模板创建新文件作为我们的 HTML,并在控制台中显示成功消息。

第八章:使用 Ajax 和 jQuery

在本章中,我们将涵盖:

  • 从另一个页面获取数据

  • 设置控制器以返回 JSON 数据

  • 创建一个 Ajax 搜索功能

  • 使用 Ajax 创建和验证用户

  • 根据复选框选择过滤数据

  • 创建一个 Ajax 通讯快讯注册框

  • 使用 Laravel 和 jQuery 发送电子邮件

  • 使用 jQuery 和 Laravel 创建可排序的表

介绍

许多现代 Web 应用程序依赖于 JavaScript 来添加动态用户交互。使用 jQuery 库和 Laravel 的内置功能,我们可以在我们自己的应用程序中轻松创建这些交互。

我们将从其他页面异步接收数据,然后发送可以保存在数据库中的数据。

从另一个页面获取数据

在我们的应用程序中,可能会有时候我们需要从另一个页面访问一些 HTML。使用 Laravel 和 jQuery,我们可以轻松实现这一点。

准备工作

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

如何做...

要完成这个步骤,请按照给定的步骤进行操作:

  1. 打开routes.php文件:
Route::get('getting-data', function()
{
  return View::make('getting-data');
});

Route::get('tab1', function()
{
  if (Request::ajax()) {
  return View::make('tab1');
}
  return Response::error('404');
});

Route::get('tab2', function()
{
  if (Request::ajax()) {
  return View::make('tab2');
}
  return Response::error('404');
});
  1. views目录中,创建一个名为tab1.php的文件:
<h1>CHAPTER 1 - Down the Rabbit-Hole</h1>
<p>
  Alice was beginning to get very tired of sitting by her sister on the bank,and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice 'without pictures or conversation?'
</p>
<p>
  So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her.
</p>
  1. views目录中,创建一个名为tab2.php的文件:
<h1>Chapter 1</h1>
<p>"TOM!"</p>
<p>No answer.</p>
<p>"TOM!"</p>
<p>No answer.</p>
<p>"What's gone with that boy,  I wonder? You TOM!"</p>
<p>No answer.</p>
<p>
  The old lady pulled her spectacles down and looked over them about the room; 
  then she put them up and looked out under them. She seldom or never looked 
  through them for so small a thing as a boy; they were her state pair, 
  the pride of her heart, and were built for "style," not service—she could 
  have seen through a pair of stove-lids just as well. She looked perplexed 
  for a moment, and then said, not fiercely, but still loud enough for the 
  furniture to hear:
</p>
<p>"Well, I lay if I get hold of you I'll—"</p>
<p>
  She did not finish, for by this time she was bending down and punching 
  under the bed with the broom, and so she needed breath to punctuate 
  the punches with. She resurrected nothing but the cat.
</p>
  1. views目录中,创建一个名为getting-data.php的文件:
<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title>Getting Data</title>
  <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
</head>
<body>
<ul>
  <li><a href="#" id="tab1" class="tabs">Alice In Wonderland</a></li>
  <li><a href="#" id="tab2" class="tabs">Tom Sawyer</a></li>
</ul>
<h1 id="title"></h1>
<div id="container"></div>
<script>
  $(function() {
  $(".tabs").on("click", function(e) {e.preventDefault();
  var tab = $(this).attr("id");
  var title = $(this).html();
  $("#container").html("loading…");
  $.get(tab, function(data) {
  $("#title").html(title);
  $("#container").html(data);
});
});
});
</script>
</body>
</html>
  1. http://{yourserver}/getting-data页面查看页面,并单击链接以加载内容。

它是如何工作的...

我们首先设置我们的路由。我们的第一个路由将显示链接,当我们点击它们时,内容将加载到页面中。我们的下两个路由将保存要在主页面上显示的实际内容。为了确保这些页面不能直接访问,我们使用Request::ajax()方法来确保只接受 Ajax 请求。如果有人试图直接访问页面,它将把他们发送到错误页面。

我们的两个视图文件将包含一些书籍摘录。由于这将加载到另一个页面中,我们不需要完整的 HTML。然而,我们的主页面是一个完整的 HTML 页面。我们首先通过使用来自 Google 的内容传送网络CDN)加载 jQuery。然后,我们有一个我们想要使用的书籍列表。为了使事情变得更容易一些,链接的 ID 将对应于我们创建的路由。

当有人点击链接时,脚本将使用 ID 并从具有相同名称的路由获取内容。结果将加载到我们的container div 中。

设置控制器以返回 JSON 数据

当我们使用 JavaScript 访问数据时,最简单的方法之一是使用 JSON 格式的数据。在 Laravel 中,我们可以从我们的控制器中返回 JSON,以供我们在另一个页面上的 JavaScript 使用。

准备工作

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

如何做...

对于这个步骤,请按照给定的步骤进行操作:

  1. controllers目录中,创建一个名为BooksController.php的文件:
<?php

  class BooksController extends BaseController {

  public function getIndex()
{
  return View::make('books.index');
}

  public function getBooks()
{
  $books = array('Alice in Wonderland','Tom Sawyer','Gulliver\'s Travels','Dracula','Leaves of Grass');
  return Response::json($books);
}
}
  1. routes.php中,注册书籍控制器
Route::controller('books', 'BooksController');
  1. views目录中,创建一个名为books的文件夹,在该文件夹中创建一个名为index.php的文件:
<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title>Show Books</title>
  <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
</head>
<body>
<a href="#" id="book-button">Load Books</a>
<div id="book-list"></div>
<script>
$(function() {
$('#book-button').on('click', function(e) {e.preventDefault();
$('#book-list').html('loading...');
$.get('books/books', function(data) {var book_list = '';
$.each(data, function(){book_list += this + '<br>';
})
$("#book-list").html(book_list);
$('#book-button').hide();
});
});
});
</script>
</body>
</html>

它是如何工作的...

我们首先为我们的书籍列表创建一个 RESTful 控制器,它扩展了我们的BaseController类。我们的控制器有两个方法:一个用于显示列表,一个用于返回格式化的列表。我们的getBooks()方法使用数组作为我们的数据源,并且我们使用 Laravel 的Response::json()方法来自动为我们执行正确的格式化。

在我们的主页面上,我们在 JavaScript 中对页面进行get请求,接收 JSON,并循环遍历结果。当我们循环时,我们将书籍添加到 JavaScript 变量中,然后将列表添加到我们的book-list div 中。

还有更多...

我们的列表可以来自任何数据源。我们可以添加数据库功能,甚至调用 API。当我们使用 Laravel 的 JSON 响应时,该值将以正确的格式和正确的标头进行格式化。

创建一个 Ajax 搜索功能

如果我们想在应用程序中搜索信息,异步执行搜索可能会很有用。这样,用户就不必转到新页面并刷新所有资产。使用 Laravel 和 JavaScript,我们可以以非常简单的方式执行这个搜索。

准备工作

对于这个教程,我们需要一个正常安装的 Laravel。

如何操作...

要完成这个教程,请按照以下步骤进行:

  1. controllers目录中,创建一个名为SearchController.php的文件:
<?php

class SearchController extends BaseController {

  public function getIndex()
{
  return View::make('search.index');
}

  public function postSearch()
{
  $return = array();
  $term = Input::get('term');

  $books = array(array('name' => 'Alice in Wonderland', 'author' => 'Lewis Carroll'),array('name' => 'Tom Sawyer', 'author' => 'Mark Twain'),array('name' => 'Gulliver\'s Travels', 'author' =>'Jonathan Swift'),array('name' => 'The Art of War', 'author' => 'Sunzi'),array('name' => 'Dracula', 'author' => 'Bram Stoker'),array('name' => 'War and Peace', 'author' =>'LeoTolstoy'),);

foreach ($books as $book) {
if (stripos($book['name'], $term) !== FALSE) $return[] =$book;
}

return Response::json($return);
}
}
  1. routes.php文件中,注册控制器:
  Route::controller('search', 'SearchController');
  1. views目录中,创建一个名为search的文件夹,在该文件夹中,创建一个名为index.php的文件:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>AJAX Search</title>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
</head>
<body>
<h1>Search</h1>
<form id="search-form">
<input name="search" id="term"> <input type="submit">
</form>
<div id="results"></div>
<script>
  $(function() {
  $("#search-form").on("submit", function(e) {e.preventDefault();
  var search_term = $("#term").val();
  var display_results = $("#results");
  display_results.html("loading...");
  var results = '';
  $.post("search/search", {term: search_term}, function(data) {if (data.length == 0) {results = 'No Results';
  } else {
  $.each(data, function() {
  results += this.name + ' by ' + this.author + '<br>';
});
}
display_results.html(results);
});
})
});
</script>
</body>
</html>

它是如何工作的...

我们首先创建一个包含两种方法的 RESTful 控制器:一个用于我们的主页面,一个用于处理搜索。在我们的主页面上,我们有一个单一的text字段和一个submit按钮。当表单提交时,我们的 JavaScript 将把表单发布到我们的搜索页面。如果有结果,它将循环遍历它们,并在我们的results div 中显示它们。

对于我们的postSearch()方法,我们使用一个数组作为我们的数据源。当进行搜索时,我们然后循环遍历数组,看看字符串是否与我们的标题匹配。如果是,该值将被添加到一个数组中,并将该数组作为 JSON 返回。

使用 Ajax 创建和验证用户

当用户来到我们的应用程序时,我们可能希望他们在不需要导航到另一个页面的情况下注册或登录。使用 Laravel 内的 Ajax,我们可以提交用户的表单并异步运行验证。

准备工作

对于这个教程,我们需要一个正常安装的 Laravel,以及一个正确配置的 MySQL 数据库。我们还需要向数据库添加一个用户表,可以使用以下代码完成:

CREATE TABLE users (id int(10) unsigned NOT NULL AUTO_INCREMENT,email varchar(255) DEFAULT NULL,password char(60) DEFAULT NULL,PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

如何操作...

要完成这个教程,请按照给定的步骤进行:

  1. controllers目录中,创建一个名为UsersController.php的文件:
<?php
class UsersController extends BaseController {
  public function getIndex()
  {
  return View::make('users.index');
  }

  public function postRegister()
  {
  $rules = array('email' => 'required|email','password' => 'required|min:6');

  $validation = Validator::make(Input::all(), $rules);

  if ($validation->fails())
  {
  return Response::json($validation->errors()->toArray());
}
else
{
DB::table('users')->insert(array('email' => Input::get('email'),'password' => Hash::make(Input::get('password'))));
return Response::json(array('Registration is complete!'));
}
}
}
  1. routes.php中注册控制器:
 **Route::controller('users', 'UsersController');**

  1. views目录中,创建一个名为users的文件夹,在该文件夹中,创建一个名为index.php的文件:
<!doctype html>
<html lang="en">
  <head>
  <meta charset="utf-8">
  <title>User Register</title>
  <script type="text/javascript"src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
  </head>
  <body>
  <form id="register">
  <label for="email">Your email:</label> 
  <input type="email" name="email" id="email"><br>
  <label for="password">Your password:</label> 
  <input type="password" name="password" id="password"><br>
  <input type="submit">
  </form>
  <div id="results"></div>
  <script>
  $(function(){
  $("#register").on("submit", function(e) {e.preventDefault();
  var results = '';
  $.post('users/register', {email: $("#email").val(), password:$("#password").val()}, function(data) {
  $.each(data, function(){results += this + '<br>';
});
  $("#results").html(results);
});
});
});
</script>
  </body>
</html>

它是如何工作的...

要开始这个教程,我们创建一个主页面,用于容纳用户注册表单。当表单提交时,它将发布到我们的postRegister()方法,并将任何结果返回到results div。

postRegister()方法首先设置我们验证的规则。在这种情况下,我们希望确保两个字段都有值,电子邮件必须有效,并且密码必须至少为 6 个字符。如果验证失败,我们将错误作为 JSON 编码的字符串发送回来,我们的主页面将显示错误。如果一切正常,我们将一切保存到数据库并返回成功消息。

还有更多...

如果我们不希望任何其他页面向我们的方法发布数据,我们可以添加一个Request::ajax()条件。这意味着只有 Ajax 调用才会被我们的方法处理。

根据复选框选择过滤数据

在向用户显示数据时,允许他们过滤数据可能会很方便。因此,我们不必让用户每次都点击提交并重新加载页面,我们可以使用 Ajax 来进行所有的过滤。对于这个教程,我们将制作一个书籍列表,并允许用户根据流派进行过滤。

准备工作

对于这个教程,我们需要一个标准的 Laravel 安装,配置为与数据库一起工作。我们需要通过运行以下 SQL 语句来设置一个要使用的表:

DROP TABLE IF EXISTS books;
CREATE TABLE books (id int(10) unsigned NOT NULL AUTO_INCREMENT,name varchar(255) DEFAULT NULL,author varchar(255) DEFAULT NULL,genre varchar(255) DEFAULT NULL,PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

  INSERT INTO books VALUES ('1', 'Alice in Wonderland', 'Lewis Carroll', 'fantasy');
  INSERT INTO books VALUES ('2', 'Tom Sawyer', 'Mark Twain', 'comedy');
  INSERT INTO books VALUES ('3', 'Gulliver\'s Travels', 'Jonathan Swift', 'fantasy');
  INSERT INTO books VALUES ('4', 'The Art of War', 'Sunzi', 'philosophy');
  INSERT INTO books VALUES ('5', 'Dracula', 'Bram Stoker', 'horror');
  INSERT INTO books VALUES ('6', 'War and Peace', 'Leo Tolstoy', 'drama');
  INSERT INTO books VALUES ('7', 'Frankenstein', 'Mary Shelley', 'horror');
  INSERT INTO books VALUES ('8', 'The Importance of Being Earnest', 'Oscar Wilde', 'comedy');
  INSERT INTO books VALUES ('9', 'Peter Pan', 'J. M. Barrie', 'fantasy');

如何操作...

要完成这个教程,请按照以下步骤进行:

  1. controllers目录中,创建一个名为BooksController.php的新文件:
<?php
class BooksController extends BaseController {
  public function getIndex()
{
  return View::make('books.index');
}

  public function postBooks()
{
  if (!$genre = Input::get('genre')) {
  $books = Book::all();
  } else {
  $books = Book::whereIn('genre', $genre)->get();
}
return $books;
}
}
  1. routes.php文件中注册books控制器:
 **Route::controller('books', 'BooksController');**

  1. views目录中,创建一个名为books的新文件夹,在该文件夹中,创建一个名为index.php的文件:
<!doctype html>
<html lang="en">
  <head>
  <meta charset="utf-8">
  <title>Books filter</title>
  <scriptsrc="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  </head>
  <body>
  <form id="filter">
  Comedy: <input type="checkbox" name="genre[]" value="comedy"><br>
  Drama: <input type="checkbox" name="genre[]" value="drama"><br>
  Fantasy: <input type="checkbox" name="genre[]" value="fantasy"><br>
  Horror: <input type="checkbox" name="genre[]" value="horror"><br>
  Philosophy: <input type="checkbox" name="genre[]" value="philosophy"><br>
  </form>
  <hr>
  <h3>Results</h3>
  <div id="books"></div>
  <script>
  $(function(){
  $("input[type=checkbox]").on('click', function() {var books = '';
  $("#books").html('loading...');
  $.post('books/books', $("#filter").serialize(), function(data){$.each(data, function(){books += this.name + ' by ' + this.author + ' (' + this.genre + ')<br>';
});
$("#books").html(books);
});
});
});
</script>
</body>
</html>
  1. models目录中,创建一个名为Book.php的文件:
<?php
class Book extends Eloquent {
}
  1. 在浏览器中,转到http://{my-server}/books,并点击一些复选框以查看结果。

它是如何工作的...

在我们的数据库设置好之后,我们从我们的主列表页面开始。这个页面有许多复选框,每个值对应于我们书籍表中的一个流派。当一个框被选中时,表单会异步提交到我们的postBooks()方法。我们使用这些结果,循环遍历它们,并在我们的booksdiv 中显示它们。

我们的postBooks()方法首先确保实际提交了一个流派。如果没有,这意味着一切都未被选中,它将返回所有的书籍。如果有选中的内容,我们从数据库中获取与选中值匹配的所有内容。由于 Laravel 以 JSON 格式提供了原始返回的数据,我们然后返回结果,在我们的索引中,结果被正确显示。

创建一个 Ajax 新闻订阅框

让用户加入我们的电子邮件列表的一种方法是让他们通过我们的网站进行注册。在这个教程中,我们将使用 MailChimp 的 API 和一个模态窗口来显示一个注册表单,并通过 Ajax 调用发送它。

准备工作

对于这个教程,我们需要一个标准的 Laravel 安装。我们还将使用 MailChimp API 进行新闻订阅;可以在www.mailchimp.com创建免费帐户和 API 密钥。

如何做...

要完成这个教程,请按照给定的步骤进行操作:

  1. 打开composer.json文件,并更新require部分以类似以下代码:
  "require": {
  "laravel/framework": "4.0.*",
  "rezzza/mailchimp": "dev-master"
}
  1. 在命令行窗口中,位于 artisan 文件的位置,使用以下命令更新 Composer:
 **php composer.phar update**

  1. app/config目录中,创建一个名为mailchimp.php的文件:
<?php

return array('key' => '12345abcde-us1','list' => '123456789'
);
  1. views目录中,创建一个名为signup.php的文件:
<!doctype html>
<html lang="en">
  <head>
  <meta charset="utf-8">
  <title>Newsletter Signup</title>
  <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" rel="stylesheet">
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
  <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/js/bootstrap.min.js"></script>
  </head>
  <body>
  <p>
  <a href="#signupModal" role="button" class="btn btn-info" data-toggle="modal">Newsletter Signup</a>
  </p>
  <div id="results"></div>
  <div id="signupModal" class="modal hide fade">
  <div class="modal-header">
  <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
  <h3>Sign-up for our awesome newsletter!</h3>
  </div>
  <div class="modal-body">
  <p>
  <form id="newsletter_form">
  <label>Your First Name</label>
  <input name="fname"><br>
  <label>Last Name</label>
  <input name="lname"><br>
  <label>Email</label>
  <input name="email">
  </form>
  </p>
  </div>
  <div class="modal-footer">
  <a href="#" class="btn close" data-dismiss="modal">Close</a>
  <a href="#" class="btn btn-primary" id="newsletter_submit">Signup</a>
  </div>
  </div>
  <script>
  $(function(){
  $("#newsletter_submit").on('click', function(e){e.preventDefault();
  $("#results").html("loading...");
  $.post('signup-submit', $("#newsletter_form").serialize(), function(data){
  $('#signupModal').modal('hide');
  $("#results").html(data);
});
});
});
  </script>
  </body>
</html>
  1. routes.php文件中,添加我们需要的路由,使用以下代码:
Route::get('signup', function()
{
  return View::make('signup');
});

Route::post('signup-submit', function()
{
  $mc = new MCAPI(Config::get('mailchimp.key'));

  $response = $mc->listSubscribe('{list_id}',Input::get('email'),array('FNAME' => Input::get('fname'),'LNAME' => Input::get('lname')
)
);

if ($mc->errorCode){
return 'There was an error: ' . $mc->errorMessage;
} else {
return 'You have been subscribed!';
}
});

它是如何工作的...

我们首先通过使用 MailChimp SDK 的 composer 版本将 MailChimp 包安装到我们的应用程序中。然后我们需要创建一个配置文件来保存我们的 API 密钥和我们想要使用的列表 ID。

我们的注册页面将利用 jQuery 和 Bootstrap 进行处理和显示。由于我们只想在用户想要注册时显示表单,我们有一个单独的按钮,当点击时,将显示一个带有我们表单的模态窗口。表单将包括名字、姓氏和电子邮件地址。

当注册表单被提交时,我们序列化数据并将其发送到我们的signup-submit路由。一旦我们得到一个响应,我们隐藏模态窗口并在我们的页面上显示结果。

在我们的signup-submit路由中,我们尝试使用输入的信息订阅用户。如果我们得到一个响应,我们检查响应是否包含错误。如果有错误,我们将其显示给用户,如果没有,我们显示成功消息。

还有更多...

我们的signup-submit路由没有对表单输入进行任何验证。要包括验证,请查看使用 Ajax 创建和验证用户教程中的示例。

另请参阅

  • 使用 Ajax 创建和验证用户教程

使用 Laravel 和 jQuery 发送电子邮件

当创建联系表单时,我们可以选择让用户异步发送表单。使用 Laravel 和 jQuery,我们可以在不需要用户转到不同页面的情况下提交表单。

准备工作

对于这个教程,我们需要一个标准的 Laravel 安装和正确配置我们的邮件客户端。我们可以在app/config/mail.php文件中更新我们的邮件配置。

如何做...

要完成这个教程,请按照给定的步骤进行操作:

  1. views目录中,创建一个名为emailform.php的文件,如下所示:
  <!doctype html>
  <html lang="en">
  <head>
  <meta charset="utf-8">
  <title></title>
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  </head>
  <body>
  <div id="container">
  <div id="error"></div>
  <form id="email-form">
  <label>To: </label>
  <input name="to" type="email"><br>
  <label>From: </label>
  <input name="from" type="email"><br>
  <label>Subject: </label>
  <input name="subject"><br>
  <label>Message:</label><br>
  <textarea name="message"></textarea><br>
  <input type="submit" value="Send">
  </form>
  </div>
  <script>
  $(function(){
  $("#email-form").on('submit', function(e){e.preventDefault();
  $.post('email-send', $(this).serialize(), function(data){
  if (data == 0) {
  $("#error").html('<h3>There was an error</h3>');
  } else {
  if (isNaN(data)) {
  $("#error").html('<h3>' + data + '</h3>');
  } else {
  $("#container").html('Your email has been sent!');
}
}
});
});
});
</script>
</body>
</html>
  1. views文件夹中,创建我们的电子邮件模板视图文件,命名为ajaxemail.php,并使用以下代码:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
</head>
<body>
<h2>Your Message:</h2>
<div><?= $message ?></div>
</body>
</html>
  1. routes.php文件中,根据以下代码片段创建路由:
  Route::get('email-form', function()
{
  return View::make('emailform');
});
  Route::post('email-send', function()
{
  $input = Input::all();

  $rules = array('to'      => 'required|email','from'    => 'required|email','subject' => 'required','message' => 'required'
);

  $validation = Validator::make($input, $rules);

  if ($validation->fails())
{
  $return = '';
  foreach ($validation->errors()->all() as $err) {
  $return .= $err . '<br>';
}
  return $return;
}

  $send = Mail::send('ajaxemail', array('message' =>Input::get('message')), function($message)
{
  $message->to(Input::get('to'))->replyTo(Input::get('from'))->subject(Input::get('subject'));
});

  return $send;
});

它是如何工作的...

对于这个教程,我们需要正确配置我们的电子邮件客户端。我们有许多选择,包括 PHP 的mail()方法,sendmail 和 SMTP。我们甚至可以使用第三方电子邮件服务,如 mailgun 或 postmark。

我们的电子邮件表单是一个常规的 HTML 表单,包括四个字段:tofrom电子邮件地址,subject行和实际的电子邮件消息。当表单被提交时,字段被序列化并发布到我们的email-send路由。

email-send路由首先验证所有发布的输入。如果有任何验证错误,它们将作为字符串返回。如果一切正常,我们将发送我们的值到Mail::send方法,然后发送它。

回到我们的e-mail-form路由 JavaScript 中,我们检查email-send是否返回了FALSE,如果是,则显示错误。如果不是,我们需要检查响应是否是一个数字。如果不是一个数字,那意味着有验证错误,我们将它们显示出来。如果是一个数字,那意味着电子邮件发送成功,所以我们显示一个成功消息。

使用 jQuery 和 Laravel 创建可排序的表格

在处理大量数据时,将其显示在表格视图中可能会有所帮助。为了操纵数据,例如排序或搜索,我们可以使用数据表 JavaScript 库。这样,我们就不需要每次想要更改视图时都进行数据库调用。

准备工作

对于这个示例,我们需要一个标准的 Laravel 安装和一个正确配置的 MySQL 数据库。

如何做...

按照给定的步骤完成这个示例:

  1. 在我们的数据库中,使用以下命令创建一个新表并添加一些示例数据:
DROP TABLE IF EXISTS bookprices;
CREATE TABLE bookprices (id int(10) unsigned NOT NULL AUTO_INCREMENT,price float(10,2) DEFAULT NULL,book varchar(100) DEFAULT NULL,PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  INSERT INTO bookprices VALUES ('1', '14.99', 'Alice in Wonderland');
  INSERT INTO bookprices VALUES ('2', '24.50', 'Frankenstein');
  INSERT INTO bookprices VALUES ('3', '29.80', 'War andPeace');
  INSERT INTO bookprices VALUES ('4', '11.08', 'Moby Dick');
  INSERT INTO bookprices VALUES ('5', '19.72', 'The Wizard of Oz');
  INSERT INTO bookprices VALUES ('6', '45.00', 'The Odyssey');
  1. app/models目录中,创建一个名为Bookprices.php的文件,并包含以下代码片段:
<?php
class Bookprices extends Eloquent {
}
  1. routes.php文件中,按照以下代码添加我们的路由:
Route::get('table', function()
{
  $bookprices = Bookprices::all();
  return View::make('table')->with('bookprices', $bookprices);
});
  1. views目录中,创建一个名为table.php的文件,其中包含以下代码:
<!doctype html>
<html lang="en">
  <head>
  <meta charset="utf-8">
  <title></title>
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  <script src="//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>
  <link rel="stylesheet" type="text/css" href="//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css">
  </head>
  <body>
  <h1>Book List</h1>
  <table>
  <thead>
  <tr>
  <th>Price</th>
  <th>Name</th>
  </tr>
  </thead>
  <tbody>
  <?php foreach ($bookprices as $book): ?>
  <tr>
  <td><?php echo $book['price'] ?></td>
  <td><?php echo $book['book'] ?></td>
  </tr>
  <?php endforeach; ?>
  </tbody>
  </table>
  <script>
  $(function(){
  $("table").dataTable();
});
  </script>
  </body>
  </html>

它是如何工作的...

要开始这个示例,我们创建一个表来保存我们的图书价格数据。然后,我们将数据插入表中。接下来,我们创建一个Eloquent模型,以便我们可以与数据交互。然后将该数据传递到我们的视图中。

在我们的视图中,我们加载 jQuery 和dataTables插件。然后,我们创建一个表来保存我们的数据,然后循环遍历数据,将每条记录放入新行中。当我们将dataTable插件添加到我们的表中时,它将自动为每个列添加排序。

还有更多...

Datatables是一个强大的 jQuery 插件,用于操纵表格数据。有关更多信息,请查看www.datatables.net上的文档。

第九章:有效使用安全和会话

在本章中,我们将涵盖:

  • 加密和解密数据

  • 哈希密码和其他数据

  • 在表单中使用 CSRF 令牌和过滤器

  • 在表单中使用高级验证

  • 构建购物车

  • 使用 Redis 保存会话

  • 使用基本会话和 cookies

  • 创建安全的 API 服务器

介绍

安全是我们在构建 Web 应用程序时需要考虑的最重要的事情之一,特别是如果我们处理敏感的用户信息。Laravel 为我们提供了许多方法来保护我们的应用程序安全。

在本章中,我们将看看掩盖敏感数据的各种方法,如何保护我们的表单免受跨站点攻击,以及如何保护 API。我们还将看到如何使用会话来构建购物车,并使用 Redis 存储会话数据。

加密和解密数据

在编写处理敏感数据的应用程序时,我们经常希望加密我们存储在数据库中的任何数据。Laravel 为我们提供了解决这个问题的解决方案。

准备工作

对于这个配方,我们需要一个标准的 Laravel 安装,以及一个正确设置和配置的 MySQL 数据库。

如何做…

这是我们将使用以下步骤完成该配方的方法:

  1. app/config目录中,打开app.php文件,并确保key为空
  'key' => '',
  1. 在命令行中,转到应用程序的根目录,并使用以下命令生成一个新的密钥:
  php artisan key:generate
  1. 使用以下命令在数据库中创建一个表来保存我们的敏感信息:
CREATE TABLE accounts(
  id int(11) unsigned NOT NULL AUTO_INCREMENT,
    business varchar(255) DEFAULT NULL,
    total_revenue varchar(255) DEFAULT NULL,
    projected_revenue varchar(255) DEFAULT NULL,
    PRIMARY KEY (id)) 
    ENGINE=InnoDB DEFAULT CHARSET=utf8;

  1. 在我们的app/models目录中,通过输入以下代码创建一个名为Account.php的文件:
<?php

class Account extends Eloquent {
  protected $table = 'accounts';
  public $timestamps = false;
  public function setBusinessAttribute($business) {$this->attributes['business'] = Crypt::encrypt($business);
}

public function setTotalrevenueAttribute($total_revenue)
  {$this->attributes['total_revenue'] = Crypt::encrypt($total_revenue);
}

  public functionsetProjectedrevenueAttribute($projected_revenue)
{
  $this->attributes['projected_revenue'] = Crypt::encrypt($projected_revenue);
}

public function getBusinessAttribute()
{
  return Crypt::decrypt($this->attributes['business'])
}

public function getTotalrevenueAttribute()
{
  return number_format(Crypt::decrypt($this>attributes['total_revenue'])) ;
}

public function getProjectedrevenueAttribute()
{
  return number_format(Crypt::decrypt($this>attributes['projected_revenue']));
}
}
  1. 在我们的routes.php文件中,通过添加以下代码创建查看和提交信息的路由:
Route::get('accounts', function()
{
  $accounts = Account::all();
  return View::make('accounts')->with('accounts', $accounts);
});

Route::post('accounts', function()
{
  $account = new Account();
  $account->business = Input::get('business');
  $account->total_revenue = Input::get('total_revenue');
  $account->projected_revenue = Input::get('projected_revenue');
  $account->save();
  return Redirect::to('accounts');
});
  1. 在我们的views目录中,创建一个名为accounts.php的文件
  <form action="accounts" method="post">
  <label for="business">Business:</label><br>
  <input name="business"><br><br>
  <label for="total_revenue">Total Revenue ($):</label><br>
  <input name="total_revenue"><br><br>
  <label for="projected_revenue">Projected Revenue($):</label><br>
  <input name="projected_revenue"><br><br>
  <input type="submit">
  </form>
  <hr>
  <?php if ($accounts): ?>
  <table border="1">
  <thead>
  <tr>
  <th>Business</th>
  <th>Total Revenue</th>
  <th>Projected Revenue</th>
  </tr>
  </thead>
  <tbody>
  <?php foreach ($accounts as $account): ?>
  <tr>
  <td><?= $account->business ?></td>
  <td>$<?= $account->total_revenue ?></td>
  <td>$<?= $account->projected_revenue ?></td>
  </tr>
  <?php endforeach; ?>
  </tbody>
  </table>
  <?php endif; ?>

工作原理…

我们首先移除 Laravel 默认的密钥。然后,我们使用artisan命令为我们生成一个新的密钥,并且它会自动保存在正确的文件中。artisan命令创建了一个相当强大的密钥,所以我们不必担心自己想出一个密钥。

在为应用程序创建密钥之后,请确保不要更改它,因为如果您已经使用了一些加密,那么更改密钥将会破坏您的应用程序。

然后我们设置一个数据库表,用来保存我们的敏感数据。在这个例子中,我们将存储企业名称以及一些财务数据。

我们的下一步是设置我们的模型,使用Eloquent模型。为了让事情变得更容易一些,我们将在模型中使用 getter 和 setter,这样每当在我们的Account模型中设置一个值时,它都会自动使用 Laravel 的Crypt::encrypt类进行加密。此外,为了从数据库中获取信息,我们的模型将自动为我们解密它。

接下来,我们创建了一些路由。第一个路由将显示一个表单来添加信息,并显示数据库中已经保存的任何内容。下一个路由只是获取表单输入,并将其保存到我们的账户表中的新行中。添加信息后,我们将被重定向回账户列表和表单页面,并且新数据将显示在页面底部。

然而,如果我们查看数据库本身,我们存储的信息是不可读的文本。这样,如果有人成功入侵我们的数据库,他们也得不到太多信息。

哈希密码和其他数据

当我们将用户的密码存储在数据库中时,对密码进行哈希处理是常见的做法。这有助于防止任何未经授权访问数据库的人看到用户的密码。然而,我们可能还希望隐藏用户的电子邮件地址或其他信息,以便没有人能够访问它们。我们可以使用 Laravel 的Hash来轻松实现这一点。

准备工作

对于这个配方,我们需要一个标准的 Laravel 安装,以及一个正确设置和配置的 MySQL 数据库。

如何做…

以下是此配方的步骤…

  1. 使用以下命令设置数据库表:
CREATE TABLE register (
  id int(10) unsigned NOT NULL AUTO_INCREMENT,
  username varchar(255) DEFAULT NULL,
  email char(60) DEFAULT NULL,
  password char(60) DEFAULT NULL,
  PRIMARY KEY (id)
  ) ENGINE=InnoDB AUTO_INCREMENT=1

  1. views目录中,使用以下代码创建一个名为register.php的文件:
  <!doctype html>
  <html lang="en">
  <head>
  <meta charset="utf-8">
  <title>Register</title>
  </head>
  <body>
  <p>
  <h3>Register</h3>
  <form method="post" action="register">
  <label>User Name</label>
  <input name="username"><br>
  <label>Email</label>
  <input name="email"><br>
  <label>Password</label>
  <input name="password"><br>
  <input type="submit">
  </form>
  </p>
  <p style="border-top:1px solid #555">
  <h3>Login</h3>
  <form method="post" action="login">
  <label>User Name</label>
  <input name="username"><br>
  <label>Email</label>
  <input name="email"><br>
  <label>Password</label>
  <input name="password"><br>
  <input type="submit">
  </form>
  </p>
  <hr>
  <table border='1'>
  <?php if ($users): ?>
  <tr>
  <th>User Name</th>
  <th>Email</th>
  <th>Password</th>
  </tr>
  <?php foreach ($users as $user): ?>
  <tr>
  <td><?= $user->username ?></td>
  <td><?= $user->email ?></td>
  <td><?= $user->password ?></td>
  </tr>
  <?php endforeach; ?>
  <?php endif; ?>
  </table>
  </body>
  </html>
  1. 在我们的routes.php文件中,通过添加以下代码创建我们的路由:
Route::get('register', function()
{
  $users = DB::table('register')->get();
  return View::make('register')->with('users', $users);
});

Route::post('register', function()
{
  $data = array(
    'username' => Input::get('username'),
    'email' => Hash::make(Input::get('email')),
    'password' => Hash::make(Input::get('password')));

  DB::table('register')->insert($data);

  return Redirect::to('register');
});

Route::post('login', function()
{
  $user = DB::table('register')->where('username', '=',
    Input::get('username'))->first();
  if (!is_null($user) and Hash::check(Input::get('email'),
    $user->email) and Hash::check(Input::get('password'),
    $user->password)) {
    echo "Log in successful";
  } else {
  echo "Not able to login";
}
});

它是如何工作的...

要开始这个示例,我们首先设置一个基本的用户表,用于保存用户名、电子邮件地址和密码。在这个示例中,用户名是唯一需要以常规文本形式存在的内容。

在我们的视图中,我们将创建两个表单——一个用于注册,一个用于登录。为了显示来自数据库的原始数据,我们还将显示所有用户的列表,以及他们的电子邮件和密码在表中的样子。

当我们提交注册表单时,信息将被发布到我们的注册路由并放入一个数组中。对于电子邮件和密码,我们使用 Laravel 的Hash::make()函数进行哈希处理。然后,我们将数组插入到我们的注册表中,并重定向回表单和列表页面。

重定向后,我们将看到新添加的行,我们的电子邮件和密码已经被哈希处理,并且是一个无法识别的字符串。有趣的是,通过哈希处理的方式,我们可以使用完全相同的数据添加两行,哈希值将完全不同。

接下来,我们可以尝试使用用户名、电子邮件和密码登录。该路由将从与用户名对应的表中抓取一行,然后对输入值和数据库结果运行 Laravel 的Hash::check()函数。如果通过,它将返回TRUE,我们可以继续进行应用程序。

还有更多...

要在生产环境中使用此示例,我们需要对输入进行一些验证。我们可能还希望利用Eloquent ORM来使哈希处理变得更容易一些。

如果我们不需要隐藏用户的电子邮件,我们也可以使用 Laravel 内置的Auth::attempt()方法。关于此方法的更多信息可以在 Laravel 网站上找到:laravel.com/docs/security#authenticating-users

在表单中使用 CSRF 令牌和过滤器

网络表单以黑客试图访问网站或用户信息而臭名昭著。为了使我们的表单更安全,我们可以使用内置在 Laravel 中的跨站请求伪造CSRF)策略。这将阻止来自用户会话外部的表单提交。

准备工作

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

如何做...

以下是完成此示例的步骤:

  1. routes.php文件中,通过以下代码创建用于保存和处理表单的路由:
Route::get('cross-site', function()
{
  return View::make('cross-site');
});

Route::post('cross-site', array('before' => 'csrf',function()
{
  echo 'Token: ' . Session::token() . '<br>';
  dd(Input::all());
}));
  1. filters.php文件中,确保csrf令牌的filter存在,如下所示:
Route::filter('csrf', function()
{
  if (Session::token() != Input::get('_token'))
{
  throw new Illuminate\Session\TokenMismatchException;
}
});
  1. 在我们的views目录中,创建一个名为cross-site.php的文件,并按以下代码添加两个测试表单:
  <!doctype html>
  <html lang="en">
  <head>
  <meta charset="utf-8">
  <title>CSRF Login</title>
  </head>
  <body>
  <p>
  <h3>CSRF Login</h3>
  <?= Form::open(array('url' => 'cross-site', 'method' =>'post')) ?>
  <?= Form::token() ?>
  <?= Form::label('email', 'Email') ?>
  <?= Form::text('email') ?>
  <?= Form::label('password', 'Password') ?>
  <?= Form::password('password') ?>
  <?= Form::submit('Submit') ?>
  <?= Form::close() ?>
  </p>
  <hr>
  <p>
  <h3>CSRF Fake Login</h3>
  <?= Form::open(array('url' => 'cross-site', 'method' =>'post')) ?>
  <?= Form::hidden('_token', 'smurftacular') ?>
  <?= Form::label('email', 'Email') ?>
  <?= Form::text('email') ?>
  <?= Form::label('password', 'Password') ?>
  <?= Form::password('password') ?>
  <?= Form::submit('Submit') ?>
  <?= Form::close() ?>
  </p>
  </body>
  </html>
  1. 在浏览器中,转到http://{your-server}/cross-site(其中{your-server}是我们正在使用的服务器的名称),然后提交每个表单以查看结果。

它是如何工作的...

我们的第一步是为我们的 CSRF 表单创建路由。在表单中,我们只需要添加Form::token()函数;这将插入一个隐藏字段,名称为_token,值为用户会话 ID。对于提交表单的路由,我们在路由中添加csrf前过滤器。如果请求被确定为伪造,页面将返回服务器错误。

我们的下一个表单是一个示例,展示了如果请求试图被伪造会发生什么。对于这个表单,我们手动添加隐藏字段并添加一些随机值,而不是使用Form::token()函数。然后当我们提交表单时,页面将显示一个失败消息,并显示TokenMismatchException错误。

还有更多...

当您使用Form::open()函数时,Laravel 还会自动生成一个csrf令牌,因此您不需要手动添加它。

在表单中使用高级验证

有时我们需要验证表单中不属于框架的内容。这个配方将向您展示如何构建自定义验证规则并应用它。

准备工作

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

如何做...

以下是完成这个配方的步骤:

  1. views目录中,创建一个名为valid.php的文件,使用以下代码来保存我们的表单:
  <!doctype html>
  <html lang="en">
  <head>
  <meta charset="utf-8">
  <title>Custom Validation</title>
  </head>
  <body>
  <p>
  <?php if ($errors): ?>
  <?php echo $errors->first('email') ?>
  <?php echo $errors->first('captain') ?>
  <?php endif; ?>
  </p>
  <p>
  <h3>Custom Validation</h3>
  <?= Form::open(array('url' => 'valid', 'method' => 'post'))?>
  <?= Form::label('email', 'Email') ?>
  <?= Form::text('email') ?><br><br>
  <?= Form::label('captain', 'Your favorite captains (choosethree)') ?><br>
  <?= 'Pike: ' . Form::checkbox('captain[]', 'Pike') ?><br>
  <?= 'Kirk: ' . Form::checkbox('captain[]', 'Kirk') ?><br>
  <?= 'Picard: ' . Form::checkbox('captain[]', 'Picard')?><br>
  <?= 'Sisko: ' . Form::checkbox('captain[]', 'Sisko') ?><br>
  <?= 'Janeway: ' . Form::checkbox('captain[]', 'Janeway')?><br>
  <?= 'Archer: ' . Form::checkbox('captain[]', 'Archer')?><br>
  <?= 'Crunch: ' . Form::checkbox('captain[]', 'Crunch')?><br>
  <?= Form::submit('Submit') ?>
  <?= Form::close() ?>
  </p>
  </body>
  </html>
  1. routes.php文件中,使用以下代码创建我们的路由:
Route::get('valid', function()
{
  return View::make('valid');
});
Route::post('valid', function()
{
  $rules = array('email' => 'required|email','captain' => 'required|check_three');
  $messages = array('check_three' => 'Thou shalt choose three captains. Nomore. No less. Three shalt be the number thou shaltchoose, and the number of the choosing shall bethree.',);
  $validation = Validator::make(Input::all(), $rules,$messages);
  if ($validation->fails())
  {
  return Redirect::to('valid')->withErrors($validation);
}
  echo "Form is valid!";
});
  1. 同样在routes.php文件中,按照以下代码创建我们的自定义验证:
  Validator::extend('check_three', function($attribute,$value, $parameters)
{
  return count($value) == 3;
});

它是如何工作的...

首先,我们在视图中创建表单。我们要求一个有效的电子邮件和确切地三个复选框被选中。由于没有确切地三个复选框的 Laravel 验证方法,我们需要创建一个自定义验证。

我们的自定义验证接受输入数组并进行简单计数。如果计数达到三个,它返回TRUE。如果不是,则返回FALSE并且验证失败。

回到我们的表单处理路由,我们只需要将我们创建的自定义验证器的名称添加到我们的验证规则中。如果我们想设置自定义消息,也可以添加。

还有更多...

这个配方的额外验证器在routes.php文件中,为了简单起见。如果我们有多个自定义验证器,将它们放在自己的验证器文件中可能是一个更好的主意。为此,我们应该在app目录中创建一个名为validator.php的文件,并添加任何我们想要的代码。然后,打开app/start目录中的global.php文件,在文件的最后添加require app_path().'/validator.php'函数。这将自动加载所有的验证器。

构建一个购物车

电子商务在网络上是一个巨大的业务。大多数电子商务网站的一个重要部分是使用购物车系统。这个配方将介绍如何使用 Laravel 会话来存储销售商品并构建购物车。

准备工作

对于这个配方,我们需要一个标准的 Laravel 安装,以及一个正确设置和配置的 MySQL 数据库。

如何做...

要完成这个配方,按照以下给定的步骤进行操作:

  1. 在我们的数据库中,使用以下 SQL 代码创建一个表并添加一些数据:
CREATE TABLE items (
    id int(10) unsigned NOT NULL AUTO_INCREMENT,
    name varchar(255) DEFAULT NULL,
    description text,
    price int(11) DEFAULT NULL,
    PRIMARY KEY (id)
    ) ENGINE=InnoDB;

  INSERT INTO items VALUES ('1', 'Lamp', 'This is a Lamp.','14');
  INSERT INTO items VALUES ('2', 'Desk', 'This is a Desk.','75');
  INSERT INTO items VALUES ('3', 'Chair', 'This is a
    Chair.', '22');
  INSERT INTO items VALUES ('4', 'Sofa', 'This is a
    Sofa/Couch.', '144');
  INSERT INTO items VALUES ('5', 'TV', 'This is a
    Television.', '89');

  1. routes.php文件中,使用以下代码为我们的购物车创建路由:
Route::get('items', function() 
{
  $items = DB::table('items')->get();
  return View::make('items')->with('items', $items)>nest('cart', 'cart', array('cart_items' =>Session::get('cart')));
});

Route::get('item-detail/{id}', function($id)
{
  $item = DB::table('items')->find($id);
  return View::make('item-detail')->with('item', $item)>nest('cart', 'cart', array('cart_items' =>Session::get('cart')));
});

Route::get('add-item/{id}', function($id)
{
  $item = DB::table('items')->find($id);
  $cart = Session::get('cart');
  $cart[uniqid()] = array ('id' => $item->id, 'name' => $item >name, 'price' => $item->price);
  Session::put('cart', $cart);
  return Redirect::to('items');
});

Route::get('remove-item/{key}', function($key)
{
  $cart = Session::get('cart');
  unset($cart[$key]);
  Session::put('cart', $cart);
  return Redirect::to('items');
});

Route::get('empty-cart', function()
{
  Session::forget('cart');
  return Redirect::to('items');
});
  1. views目录中,使用以下代码创建一个名为items.php的文件:
  <!doctype html>
  <html lang="en">
  <head>
  <meta charset="utf-8">
  <title>Item List</title>
  </head>
  <body>
  <div>
  <?php foreach ($items as $item): ?>
  <p>
  <a href="item-detail/<?= $item->id ?>">
  <?= $item->name ?>
  </a> --
  <a href="add-item/<?= $item->id ?>">Add to Cart</a>
  </p>
  <?php endforeach; ?>
  </div>
  <?php $cart_session = Session::get('cart') ?>
  <?php if ($cart_session): ?>
  <?= $cart ?>
  <?php endif; ?>
  </body>
  </html>
  1. views目录中,按照给定的代码创建一个名为item-detail.php的文件:
  <!doctype html>
  <html lang="en">
  <head>
  <meta charset="utf-8">
  <title>Item: <?= $item->name ?></title>
  </head>
  <body>
  <div>
  <h2><?= $item->name ?></h2>
  <p>Price: <?= $item->price ?></p>
  <p>Description: <?= $item->description ?></p>
  <p>
  <a href="../add-item/<?= $item->id ?>">Add to Cart</a>
  </p>
  <p><a href="../items">Item list</a></p>
  </div>
  <? if (Session::has('cart')): ?>
  <?= $cart ?>
  <? endif; ?>
  </body>
  </html>
  1. views目录中,创建一个名为cart.php的文件,使用以下代码:
  <div class="cart" style="border: 1px solid #555">
  <?php if ($cart_items): ?>
  <?php $price = 0 ?>
  <ul>
  <?php foreach ($cart_items as $cart_item_key =>$cart_item_value): ?>
  <?php $price += $cart_item_value['price']?>
  <li>
  <?= $cart_item_value['name'] ?>: 
  <?= $cart_item_value['price'] ?> (<a href="remove-item/<?= $cart_item_key ?>">remove</a>)
  </li>
  <?php endforeach; ?>
  </ul>
  <p><strong>Total: </strong> <?= $price ?></p>
  <?php endif; ?>
  </div>
  1. 现在,我们可以在浏览器中输入http://{your-server}/items来查看来自我们数据库的项目列表,链接到它们的详细页面,并有一个选项将它们添加到购物车。添加到购物车后,它们将显示在页面底部。

它是如何工作的...

要开始这个配方,我们需要设置一个将保存我们想要添加到购物车的项目的数据库表。我们还将添加一些测试项目,这样我们就有一些数据可以使用。

在我们的第一个路由中,我们获取表中所有现有的项目并显示它们。我们还嵌套了一个购物车视图,将显示我们已经添加的项目。在嵌套视图中,我们还发送我们的购物车会话,以便列表可以填充。

我们的下一个路由做了类似的事情,但它只接受一个项目并显示完整信息。

下一个路由实际上添加了项目。首先,我们根据其 ID 从数据库中获取项目。然后我们将现有的购物车会话保存到一个变量中,以便我们可以操作它。我们使用 php 的uniqid()函数作为键将项目添加到数组中。然后我们将cart数组放回Session并将其重定向。

如果我们想要删除一个项目,首先我们要找到获取项目的 ID 并从cart数组中删除它。另一种方法是只删除所有会话并重新开始。

在我们的视图中,我们还会注意到,只有在购物车中实际有东西的情况下,才允许显示cart列表。

还有更多...

这个配方可以很容易地扩展为更全面的功能。例如,如果我们多次点击同一项,可以存储每个项目的总数,而不是添加新记录。这样,我们可以在项目旁边添加一个要求数量的表单字段。

使用 Redis 保存会话

Redis 是一种流行的键/值数据存储,速度相当快。Laravel 包括对 Redis 的支持,并且可以轻松地与 Redis 数据交互。

准备工作

对于这个配方,我们需要一个正确配置和运行的 Redis 服务器。关于这方面的更多信息可以在redis.io/找到。

如何做...

按照以下步骤完成这个配方:

  1. 在我们的routes.php文件中,按照以下代码创建路由:
Route::get('redis-login', function()
{
  return View::make('redis-login');
});

Route::post('redis-login', function()
{
  $redis = Redis::connection();
  $redis->hset('user', 'name', Input::get('name'));
  $redis->hset('user', 'email', Input::get('email'));
  return Redirect::to('redis-view');
});

Route::get('redis-view', function()
{
  $redis = Redis::connection();
  $name = $redis->hget('user', 'name');
  $email = $redis->hget('user', 'email');
  echo 'Hello ' . $name . '. Your email is ' . $email;
});
  1. views目录中,创建一个名为redis-login.php的文件,其中包含以下代码:
  <!doctype html>
  <html lang="en">
  <head>
  <meta charset="utf-8">
  <title>Redis Login</title>
  </head>
  <body>
  <p>
  <h3>Redis Login</h3>
  <?= Form::open(array('url' => 'redis-login', 'method' =>'post')) ?>
  <?= Form::label('name', 'Your Name') ?>
  <?= Form::text('name') ?>
  <?= Form::label('email', 'Email') ?>
  <?= Form::text('email') ?>
  <?= Form::submit('Submit') ?>
  <?= Form::close() ?>
  </p>
  </body>
  </html>
  1. 现在,我们可以打开浏览器,转到http://{your-server}/redis-login,并填写表单。提交后,我们将显示来自 Redis 的信息。

工作原理...

我们的第一步是创建一个简单的表单,用于将数据输入到 Redis 中。在我们的redis-login路由中,我们使用一个视图,该视图将要求输入姓名和电子邮件地址,并在提交时将发布到redis-login路由。

发布后,我们使用Redis::connection()函数创建一个新的 Redis 实例,该函数将使用我们的app/config/database.php文件中找到的默认设置。为了将信息存储在 Redis 中,我们使用一个哈希并使用hset()函数设置数据。我们的 Redis 实例可以使用 Redis 接受的任何命令,因此我们可以很容易地在set()sadd()等函数之间进行选择。

一旦数据在 Redis 中,我们重定向到一个将显示数据的路由。为此,我们只需要使用键和我们添加的字段调用hget()函数。

使用基本会话和 cookie

有时我们希望在应用程序的一个页面和另一个页面之间传递数据,而不需要将信息存储在数据库中。为了实现这一点,我们可以使用 Laravel 提供的各种SessionCookie方法。

准备工作

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

如何做...

对于这个配方,按照给定的步骤:

  1. views文件夹中,创建一个名为session-one.php的文件,其中包含以下代码:
  <!DOCTYPE html>
  <html>
  <head>
  <title>Laravel Sessions and Cookies</title>
  <meta charset="utf-8">
  </head>
  <body>
  <h2>Laravel Sessions and Cookies</h2>
  <?= Form::open() ?>
  <?= Form::label('email', 'Email address: ') ?>
  <?= Form::text('email') ?>
  <br>
  <?= Form::label('name', 'Name: ') ?>
  <?= Form::text('name') ?>
  <br>
  <?= Form::label('city', 'City: ') ?>
  <?= Form::text('city') ?>
  <br>
  <?= Form::submit('Go!') ?>
  <?= Form::close() ?>
  </body>
  </html>
  1. routes.php文件中,按照以下代码创建我们的路由:
Route::get('session-one', function()
{
  return View::make('session-one');
});

Route::post('session-one', function()
{
  Session::put('email', Input::get('email'));
  Session::flash('name', Input::get('name'));
  $cookie = Cookie::make('city', Input::get('city'), 30);
  return Redirect::to('session-two')->withCookie($cookie);
});

Route::get('session-two', function()
{
  $return = 'Your email, from a Session, is 'Session::get('email') . '. <br>';
  $return .= 'You name, from flash Session, is 'Session::get('name') . '. <br>';
  $return .= 'You city, from a cookie, is ' .Cookie::get('city') . '.<br>';
  $return .= '<a href="session-three">Next page</a>';
  echo  $return;
});

Route::get('session-three', function()
{
  $return = '';

  if (Session::has('email')) {
  $return .= 'Your email, from a Session, is ' . Session::get('email') . '. <br>';
} else {
$return .= 'Email session is not set.<br>';
}

if (Session::has('name')) {
  $return .= 'Your name, from a flash Session, is ' . Session::get('name') . '. <br>';
} else {
$return .= 'Name session is not set.<br>';
}

if (Cookie::has('city')) {
  $return .= 'Your city, from a cookie, is ' . Cookie::get('city') . '. <br>';
} else {
  $return .= 'City cookie is not set.<br>';
}
  Session::forget('email');
  $return .= '<a href="session-three">Reload</a>';
  echo $return;
});

工作原理...

首先,我们创建一个简单的表单,用于提交信息到会话和 cookie。在提交值之后,我们取email字段并将其添加到常规会话中。name字段将被添加到闪存会话中,city将被添加到 cookie 中。此外,我们将设置 cookie 在 30 分钟后过期。一旦它们都设置好了,我们重定向到我们的第二个页面,并确保将 cookie 传递给返回值。

我们的第二个页面只是获取我们设置的值,并显示它们以验证它们是否被正确设置。此时,一旦请求完成,我们的闪存会话,即名称,应该不再可用。

当我们点击到第三个页面时,我们添加了一些检查,以确保会话和 cookie 仍然存在,使用has()方法。我们的emailcity应该仍然显示,但name会话不应该。然后我们使用forget()方法删除email会话。当我们重新加载页面时,我们会注意到唯一仍然显示的是city cookie。

还有更多...

闪存数据仅在我们进行的下一个请求中可用,然后被删除。但是,如果我们想保留我们的闪存数据,我们可以使用Session::reflash()命令,它也会将数据发送到我们的下一个请求。如果我们有多个闪存数据,我们还可以使用Session::keep(array('your-session-key', 'your-other-session'))函数选择保留特定会话以供下一个请求使用。

创建安全的 API 服务器

在这个食谱中,我们将创建一个简单的 API 来显示来自我们数据库的一些信息。为了控制谁可以访问数据,我们允许用户创建密钥并在其 API 请求中使用该密钥。

准备工作

对于这个食谱,我们需要一个标准的 Laravel 安装和一个配置好的 MySQL 数据库。

如何做到这一点...

要完成这个食谱,我们将按照以下给定的步骤进行:

  1. 在我们的数据库中,创建一个表来保存 API 密钥,如下面的代码所示:
CREATE TABLE api (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
 name varchar(255) DEFAULT NULL,
 api_key varchar(255) DEFAULT NULL,
 status tinyint(1) DEFAULT NULL,
 PRIMARY KEY (id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  1. 在数据库中,创建一个表以访问一些示例数据,如下面的代码所示:
CREATE TABLE shows (id int(10) unsigned NOT NULL AUTO_INCREMENT,name varchar(200) NOT NULL,year int(11) NOT NULL,created_at datetime NOT NULL,updated_at datetime NOT NULL,PRIMARY KEY (id)) ENGINE=InnoDB CHARSET=utf8;

  INSERT INTO shows VALUES ('1', 'Happy Days', '1979','2013-01-01 00:00:00', '2013-01-01 00:00:00');
  INSERT INTO shows VALUES ('2', 'Seinfeld', '1999', '2013-01-01 00:00:00', '2013-01-01 00:00:00');
  INSERT INTO shows VALUES ('3', 'Arrested Development', '2006', '2013-01-01 00:00:00', '2013-01-01 00:00:00');
  INSERT INTO shows VALUES ('4', 'Friends', '1997','2013-01-01 00:00:00', '2013-01-01 00:00:00');
  1. models目录中,创建一个名为Api.php的文件
  <?php

class Api extends Eloquent {

  public $table = 'api';
  public $timestamps = FALSE;
}
  1. models目录中,创建一个名为Show.php的文件
  <?php
class Show extends Eloquent {
}
  1. views目录中,创建一个名为api-key.php的文件
  <!DOCTYPE html>
  <html>
  <head>
  <title>Create an API key</title>
  <meta charset="utf-8">
  </head>
  <body>
  <h2>Create an API key</h2>
  <?php echo Form::open() ?>
  <?php echo Form::label('name', 'Your Name: ') ?>
  <?php echo Form::text('name') ?>
  <br>
  <?php echo Form::submit('Go!') ?>
  <?php echo Form::close() ?>
  </body>
  </html>
  1. routes.php文件中,创建路由以允许api-key注册
Route::get('api-key', function() {
  return View::make('api-key');
});

Route::post('api-key', function() {
  $api = new Api();
  $api->name = Input::get('name');
  $api->api_key = Str::random(16);
  $api->status = 1;
  $api->save();
  echo 'Your key is: ' . $api->api_key;
});
  1. routes.php中,通过以下代码创建访问api的路由:
Route::get('api/{api_key}/shows', function($api_key)
{
  $client = Api::where('api_key', '=', $api_key)->where('status', '=', 1)->first();
  if ($client) {
  return Show::all();
  } else {
  return Response::json('Not Authorized', 401);
  }
});
Route::get('api/{api_key}/show/{show_id}', function($api_key, $show_id)
{
  $client = Api::where('api_key', '=', $api_key)->where('status', '=', 1)->first();
  if ($client) {
  if ($show = Show::find($show_id)) {
  return $show;
  } else {
  return Response::json('No Results', 204);
  }
  } else {
  return Response::json('Not Authorized', 401);
  }
});
  1. 要测试它,在浏览器中,转到http://{your-server}/api-key(其中{your-server}是开发服务器的名称),并填写表单。在下一页中,复制生成的密钥。然后,转到http://{your-server}/api/{your-copied-key}/shows,应该以json格式显示节目列表。

它是如何工作的...

我们首先设置我们的表和模型。我们的 API 表将用于检查密钥,show表将是我们将使用密钥访问的测试数据。

我们的下一个任务是创建一种为我们的应用程序生成密钥的方法。在这个例子中,我们只会接受一个名称值。提交后,我们创建一个随机的 16 个字符的字符串,这将是用户的密钥。然后,我们将信息保存到表中,并将密钥显示给用户。

要使用此密钥,我们创建两个路由来显示信息。第一个路由在 URL 中使用{api_key}通配符,并将该值传递给我们的函数。然后,我们查询该密钥的数据库,并确保状态仍然是活动的。这样,如果我们决定撤销用户的密钥,我们可以将状态设置为 false,他们将无法使用 API。如果它们不存在或状态为 false,则以 401 的 HTTP 代码响应,以显示他们未经授权。否则,我们返回 Eloquent 对象,这将允许我们以json格式显示记录。

我们的第二个路由将显示单个节目的记录。对于该 URL,我们使用{api_key}通配符作为密钥,使用{show_id}通配符作为节目的 ID。我们将这些传递给函数,然后像以前一样检查密钥。如果密钥有效,我们确保具有该 ID 的节目存在,并再次使用 Eloquent 对象以json格式仅显示具有给定 ID 的节目。

还有更多...

我们还可以选择使用 Laravel 过滤器,如果我们宁愿使用 API 密钥发布。为此,我们将在filters.php文件中创建一个新的过滤器

Route::filter('api', function()
{
  if ($api_key = Input::get('api_key')) {
  $client = Api::where('api_key', '=', $api_key)->where('status', '=', 1)->first();
  if (!$client) {
  return Response::json('Not Authorized', 401);
}
  } else {
  return Response::json('Not Authorized', 401);
}
});

然后,对于我们的shows路由,我们响应一个 post 请求,并添加before过滤器,如下面的代码所示:

Route::post('api/shows', array('before' => 'api', function()
{
  return Show::all();
}));

第十章:测试和调试您的应用程序

在本章中,我们将涵盖:

  • 设置和配置 PHPUnit

  • 编写和运行测试用例

  • 使用 Mockery 测试控制器

  • 使用 Codeception 编写验收测试

  • 调试和分析您的应用程序

介绍

随着 Web 应用程序变得更加复杂,我们需要确保对现有代码所做的任何更改或更新不会对其他代码产生负面影响。检查这一点的一种方法是创建单元测试。Laravel 为我们提供了非常有用的方法来包含单元测试。

设置和配置 PHPUnit

在这个配方中,我们将看到如何安装和设置流行的 PHPUnit 测试软件包:PHPUnit。

准备工作

对于这个配方,我们需要一个正常安装的 Laravel 4。我们还需要从getcomposer.org安装 Composer 依赖工具。

如何做...

要完成这个配方,请按照给定的步骤进行操作:

  1. 在应用程序的根目录中,将以下行添加到composer.json文件中:
  "require-dev": {
  "phpunit/phpunit": "3.7.*"
  },
  1. 打开命令行窗口,导航到根目录,并使用以下行在 Composer 工具上运行更新:
 **php composer update**

  1. 安装后,在命令行窗口中使用以下命令快速测试:
 **vendor/bin/phpunit**

它是如何工作的...

我们的composer.json文件告诉 Composer 工具应安装哪些软件包。因此,我们的第一个任务是将phpunit软件包添加为要求。保存该文件后,我们将运行update命令,phpunit将被添加到我们的vendor目录。

安装后,我们可以运行命令来测试phpunit,并确保它已正确安装。Laravel 在app/tests目录中附带了一个示例测试用例,并且应该通过所有测试。

编写和运行测试用例

对于这个配方,如果我们已经安装并正常工作的 PHPUnit,我们可以编写一个测试用例,并使用 PHPUnit 来检查它是否有效。

准备工作

要运行测试用例,我们需要一个正常安装的 Laravel。我们还需要从前面的配方设置和配置 PHPUnit中安装 PHPUnit。

如何做...

要完成这个配方,请按照给定的步骤进行操作:

  1. app/tests目录中,创建一个名为MyAppTest.php的文件,并添加以下代码:
  <?php
class MyAppTest extends TestCase {

  /**
   * Testing the MyApp route
   *
   * @return void
   */
  public function testMyAppRoute()
{
  $response = $this->call('GET', 'myapp');
  $this->assertResponseOk();
  $this->assertEquals('This is my app', $response >getContent());
}
}
  1. 在命令行窗口中运行测试,我们应该在输入以下命令时得到失败的测试:
 **vendor/bin/phpunit**

  1. 在我们的routes.php文件中,添加以下代码的新路由:
  Route::get('myapp', function()
{
  return 'This is my app';
});
  1. 再次运行测试以获得通过的单元测试
 **vendor/bin/phpunit**

它是如何工作的...

当我们运行 PHPUnit 测试时,Laravel 将自动查找app/tests目录。我们首先在该目录中创建一个新文件来保存名为MyAppTest的测试,并扩展TestCase

对于这个简单的测试,我们使用call方法并在myapp路由上执行GET请求。我们首先检查的是我们收到了Ok或 200 状态代码,然后返回的内容是字符串This is my app。在这一点上,当我们运行测试时,它将失败,因为我们还没有创建路由。

接下来,我们创建我们的myapp路由并返回字符串This is my app。最后,我们重新运行测试,应该得到成功的结果。

另请参阅

  • 设置和配置 PHPUnit配方

使用 Mockery 测试控制器

有时,我们需要测试使用我们的数据库的代码。通常接受的做法是在运行单元测试时不应实际在数据库上执行实时查询。为了解决这个问题,我们可以使用 Mockery 包来伪造我们的数据。

准备工作

对于这个配方,我们需要已安装和正常工作的 Laravel,以及来自设置和配置 PHPUnit配方的 PHPUnit。

如何做...

要完成这个配方,请按照给定的步骤进行操作:

  1. 打开我们的composer.json文件,并确保包含以下代码:
  "require-dev": 
{
  "phpunit/phpunit": "3.7.*",
  "mockery/mockery": "dev-master"
},
  1. 打开命令行终端,并使用以下命令运行 Composer 更新:
 **php composer.phar update**

  1. 更新后,在app/controllers目录中,使用以下代码创建ShipsController.php文件:
<?php

class ShipsController extends BaseController {

  protected $ships; 
  public function __construct(Spaceship $ships) 
{
  $this->ships = $ships;
}

  public function showShipName()
{
  $ship = $this->ships->first();
  return $ship->name;
}
}
  1. routes.php文件中,使用以下命令添加一个路由到这个控制器:
 **Route::get('ship', 'ShipsController@showShipName');**

  1. app/tests目录中,使用以下代码创建一个名为SpaceshipTest.php的文件:
<?php

class SpaceshipTest extends TestCase {

  public function testFirstShip ()
{
  $this->call('GET', 'ship');
  $this->assertResponseOk();
}
}
  1. 回到命令行窗口,使用以下命令运行我们的测试:
 **vendor/bin/phpunit**

  1. 此时,我们将得到一个显示以下消息的失败测试:
**ReflectionException: Class Spaceship does not exist**

  1. 由于Spaceship类将是我们的模型,我们将使用 Mockery 来模拟它。使用以下代码更新SpaceshipTest类:
<?php

class SpaceshipTest extends TestCase {

  public function testFirstShip()
{
  $ship = new stdClass();
  $ship->name = 'Enterprise';

  $mock = Mockery::mock('Spaceship');
  $mock->shouldReceive('first')->once()->andReturn($ship);

  $this->app->instance('Spaceship', $mock);
  $this->call('GET', 'ship');
  $this->assertResponseOk();
}

   public function tearDown()
{
  Mockery::close();
}
}
  1. 现在,回到命令行窗口,再次运行测试,它应该通过。

工作原理...

我们首先通过 Composer 安装 Mockery 软件包。这将允许我们在整个应用程序中使用它。接下来,我们创建一个控制器,其中包含一个将显示单个飞船名称的方法。在控制器的构造函数中,我们传入要使用的模型,这种情况下将命名为Spaceship并使用 Laravel 的 Eloquent ORM。

showShipName方法中,我们将从 ORM 中获取第一条记录,然后简单地返回记录的名称。然后,我们需要创建一个指向控制器和showShipName方法的路由。

当我们首次创建测试时,我们只是发出一个GET请求,看看它是否返回一个 OK 响应。此时,由于我们还没有创建Spaceship模型,当我们运行测试时会显示错误。我们可以向数据库添加所需的表并创建模型,测试将通过。但是,在测试控制器时,我们不想担心数据库,应该只测试控制器代码是否有效。为此,我们现在可以使用 Mockery。

当我们在Spaceship类上调用first方法时,它将给我们一个包含所有返回字段的对象,因此我们首先创建一个通用对象,并将其分配给$ship控制器。然后,我们为Spaceship类创建我们的mock对象,当我们的控制器请求first方法时,mock对象将返回我们之前创建的通用对象。

接下来,我们需要告诉 Laravel,每当请求Spaceship实例时,它应该使用我们的mock对象。最后,在我们的船舶路线上调用GET,确保它返回一个 OK 响应。

另请参阅

  • 设置和配置 PHPUnit配方

使用 Codeception 编写验收测试

验收测试是测试应用程序是否向浏览器输出正确信息的有用方法。使用 Codeception 等软件包,我们可以自动化这些测试。

准备工作

对于这个配方,我们需要安装一个 Laravel 的工作副本。

如何做...

要完成此配方,请按照给定的步骤进行:

  1. 打开composer.json文件,并将以下行添加到我们的require-dev部分:
  "codeception/codeception": "dev-master",
  1. 打开命令行窗口,并使用以下命令更新应用程序:
 **php composer.phar update**

  1. 安装完成后,我们需要在终端中运行bootstrap命令,如下所示:
 **vendor/bin/codecept bootstrap app**

  1. app/tests/acceptance目录中,使用以下代码创建一个名为AviatorCept.php的文件:
<?php

$I = new WebGuy($scenario);
$I->wantTo('Make sure all the blueprints are shown');
$I->amOnPage('/');
$I->see('All The Blueprints');
  1. 在我们的主routes.php文件中,使用以下代码更新默认路由:
Route::get('/', function()
{
return 'Way of the future';
});
  1. 打开命令行窗口,并使用以下命令运行验收测试:
 **vendor/bin/codecept run –c app**

  1. 此时,我们应该看到它失败了。为了使其通过,再次更新默认路由,输入以下代码:
Route::get('/', function()
{
return 'All The Blueprints';
});
  1. 在命令行窗口中,使用以下命令再次运行测试:
 **vendor/bin/codecept run –c app**

  1. 这次应该通过。

工作原理...

我们首先通过 Composer 安装 Codeception 软件包。一旦下载完成,我们运行bootstrap命令,它将创建所有所需的文件和目录。Codeception 会自动将文件和文件夹添加到tests目录中;因此,为了确保它们被添加到 Laravel 的测试目录中,我们在bootstrap命令的末尾添加app目录。

接下来,在acceptance目录中创建一个文件来保存我们的测试。我们首先创建一个新的WebGuy对象,这是 Codeceptions 类来运行验收测试。接下来的一行描述了我们想要做的事情,在这种情况下是查看所有的蓝图。下一行告诉测试我们需要在哪个页面,这将对应我们的路由。对于我们的目的,我们只是检查默认路由。最后,我们告诉测试我们想在页面上看到什么。我们在这里放的任何文本都应该显示在页面的某个地方。

我们对默认路由的第一次尝试将显示Way of the future;因此,当运行 Codeception 测试时,它将失败。要运行测试,我们使用run命令,并确保我们使用-c标志,并指定app作为测试路径,因为我们安装了引导文件在app/tests目录内。

然后,我们可以更新路由以显示文本All The Blueprints并重新运行测试。这次,它会通过。

还有更多...

Codeception 是一个非常强大的测试套件,有许多不同的选项。要完全了解它的所有功能,请访问codeception.com/

调试和配置您的应用

如果我们想知道我们的应用在幕后是如何工作的,我们需要对其进行配置。这个步骤将展示如何向我们的 Laravel 应用添加一个配置文件。

准备工作

对于这个步骤,我们需要一个配置正确的 Laravel 工作副本和一个 MySQL 数据库。

如何做...

要完成这个步骤,请按照以下步骤进行:

  1. 打开命令行窗口,并使用artisan命令按照以下代码创建我们的迁移:
 **php artisan migrate::make create_spaceships_table –create –table="spaceships"**

  1. app/database/migrations文件夹中,打开以日期开头并以create_spaceships_table.php结尾的文件,将其用于我们的数据库表
<?php

  use Illuminate\Database\Schema\Blueprint;
  use Illuminate\Database\Migrations\Migration;

class CreateSpaceshipsTable extends Migration {

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

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

}
  1. app/database/seeds文件夹中,创建一个名为SpaceshipSeeder.php的文件,如下所示:
<?php

class SpaceshipSeeder extends Seeder {

  /**
  * Run the database seeds.
  *
  * @return void
  */
  public function run()
{
  DB::table('spaceships')->delete();

  $ships = array(
  array(
  'name'   => 'Enterprise',
  'movie'  => 'Star Trek'
),
  array(
  'name'   => 'Millenium Falcon',
  'movie'  => 'Star Wars'
),
  array(
  'name'   => 'Serenity',
  'movie'  => 'Firefly'
),
);

  DB::table('spaceships')->insert($ships);
}
}
  1. 在同一个目录中,打开DatabaseSeeder.php文件,并确保run()方法看起来像以下代码片段:
public function run()
{
  Eloquent::unguard();
  $this->call('SpaceshipSeeder');
}
  1. 回到命令行窗口,使用以下代码安装迁移并运行 seeder:
 **php artisan migrate**
 **php artisan db:seed**

  1. app/models目录中,创建一个名为Spaceship.php的文件,如下代码所示:
<?php

class Spaceship extends Eloquent{

  protected $table = 'spaceships';
}
  1. app/controllers目录中,创建一个名为ShipsController.php的文件
<?php

class ShipsController extends BaseController {

  protected $ships; 

  public function __construct(Spaceship $ships) 
  {
  $this->ships = $ships;
}

  public function showShipName()
{
  $ships = $this->ships->all();
  Log::info('Ships loaded: ' . print_r($ships, TRUE));
  return View::make('ships')->with('ships', $ships);
}
}
  1. routes.php文件中,注册路由如下命令所示:
 **Route::get('ship', 'ShipsController@showShipName');**

  1. app/views目录中,创建一个名为ships.blade.php的视图,如下代码所示:
  @foreach ($ships as $s)
  {{ $s->name }} <hr>
  @endforeach
  1. 此时,如果我们转到http://{your-dev-url}/public/ship,我们将看到船只列表。接下来,我们需要打开composer.json文件,并在require-dev部分中添加以下行:
  "loic-sharma/profiler": "dev-master"
  1. 然后在命令行窗口中,使用以下命令更新 Composer:
 **php composer.phar update**

  1. 在所有东西都下载完成后,在app/config文件夹中,打开app.php文件。在providers数组中,在代码的末尾添加以下行:
  'Profiler\ProfilerServiceProvider',
  1. 在同一个文件中,在aliases数组中,添加以下行:
  'Profiler' => 'Profiler\Facades\Profiler',
  1. 在这个文件的顶部,确保debug设置为 true,然后在浏览器中返回http://{your-dev-url}/public/shipprofiler将显示在浏览器窗口底部。

它是如何工作的...

我们的第一步是创建我们想要配置文件的页面。我们首先使用artisan命令创建一个migrations文件,然后添加 Schema 构建器代码来创建我们的 spaceships 表。完成后,我们可以使用 seeder 文件向表中添加一些信息。

完成后,我们现在可以运行迁移和 seeder,我们的表将被创建,并且所有信息已经被填充。

接下来,我们为我们的数据创建一个简单的模型和一个控制器。在控制器中,我们将简单地获取所有的船只,并将变量传递给我们的船只视图。我们还将在代码中间添加一个日志事件。这将允许我们以后调试代码,如果需要的话。

完成后,我们可以看到我们创建的船只列表。

然后,我们需要安装基于 Laravel 早期版本的性能分析器包。更新了我们的 Composer 文件后,我们注册性能分析器,这样我们的应用程序就知道它的存在;如果以后想要更多地使用它,我们还可以注册 Façade。

在我们的配置文件中,如果我们将debug设置为TRUE,那么性能分析器将在我们访问的每个页面上显示。我们可以通过简单地将debug设置为FALSE来禁用性能分析器。

还有更多...

我们还可以使用以下代码段中显示的 startTimer 和 endTimer 方法向我们的应用程序添加定时器:

  Profiler::startTimer('myTime');
  {some code}
  Profiler::endTimer('myTime');

第十一章:将第三方服务部署和集成到您的应用程序中

在本章中,我们将涵盖:

  • 创建队列并使用 Artisan 运行它

  • 将 Laravel 应用程序部署到 Pagoda Box

  • 在 Laravel 中使用 Stripe 支付网关

  • 进行 GeoIP 查找并设置自定义路由

  • 收集电子邮件地址并与第三方电子邮件服务一起使用

  • 从 Amazon S3 存储和检索云内容

介绍

Web 应用程序通常会依赖第三方服务来帮助我们的应用程序运行。使用 Composer 和 Laravel,我们可以集成现有的代码,以便与这些服务进行交互。在本章中,我们将看到如何将我们的应用程序部署到 Pagoda Box,使用 Stripe 支付,进行 GeoIP 查找,使用第三方电子邮件服务,并将内容存储到云中。

创建队列并使用 Artisan 运行它

有时我们的应用程序需要在后台执行大量工作来完成任务。我们可以将它们添加到队列中,并稍后进行处理,而不是让用户等待任务完成。有许多队列系统可用,但 Laravel 有一些非常容易实现的。在本示例中,我们将使用 IronMQ。

准备工作

对于此示例,我们将需要一个安装良好的 Laravel 4,以及 IronMQ 的 API 凭据。可以在www.iron.io/创建免费帐户。

如何做...

要完成此示例,请按照给定的步骤进行操作:

  1. app/config目录中,打开queue.php文件,将默认值设置为iron,并填写来自 IronMQ 的凭据。

  2. 打开 Laravel 的composer.json文件并更新所需部分,使其类似于以下代码片段:

"require": {
"laravel/framework": "4.0.*",
"iron-io/iron_mq": "dev-master"
}
  1. 在命令行窗口中,使用以下命令更新 composer 文件:
**php composer.phar update**

  1. 安装完成后,打开routes.php文件并创建一个命中队列的路由:
Route::get('queueships', function() {
$ships = array(
  array(
    'name' => 'Galactica',
    'show' => 'Battlestar Galactica'),
    array(
    'name' => 'Millennium Falcon',
    'show' => 'Star Wars'),
    array(
    'name' => 'USS Prometheus',
    'show' => 'Stargate SG-1')
);
$queue = Queue::push('Spaceship', array('ships' => 
$ships));
  return 'Ships are queued.';
});
  1. app/models目录中创建一个名为Spaceship.php的文件,如下面的代码所示:
<?php

class Spaceship extends Eloquent{

  protected $table = 'spaceships';

  public function fire($job, $data)
{
// Could be added to database here!
  Log::info('We can put this in the database: ' . print_r($data, TRUE));
  $job->delete();
}
}
  1. 在浏览器中,转到http://{your-url}}/public/queueships,然后刷新几次。

  2. 在 IronMQ 窗口中检查是否添加了新消息。

  3. 打开命令行窗口并运行以下命令:

 **php artisan queue:listen**

  1. 几分钟后,查看app/storage/logs文件夹,并找到带有今天日期的文件。它将打印出我们添加到队列中的数组。

它是如何工作的...

首先,我们要确保在config文件中将 IronMQ 作为我们的默认队列驱动程序。如果我们想要使用另一个队列系统,可以在这里设置。然后,我们使用 composer 将 IronMQ 包安装到我们的应用程序中。这将添加我们需要的所有文件,以及 Iron 需要工作的任何依赖项。

此时,Laravel 已经设置好了使用我们选择的任何队列系统,因此我们可以开始使用它。我们首先在我们的路由中创建一个数据数组。这可以很容易地成为表单输入,因此我们希望等待处理的其他一些数据。然后,我们使用Queue::push()方法,设置应该使用的类(Spaceship),然后传递数据到该类。

如果我们现在转到这个路由,然后检查 IronMQ 队列,我们会看到有一个作业正在等待处理。我们的下一个任务是创建一个类来处理队列。为此,我们创建一个名为Spaceship的模型。我们需要创建一个fire()方法来解析我们从队列中获取的数据。在这里,我们可以将信息保存到数据库或进行其他一些繁重的处理。现在,我们只是将数据发送到日志文件。在fire()方法的末尾,我们确保删除作业。

如果我们转到我们的queueships路由并刷新几次,我们会看到我们的队列中有多个作业,但我们还没有处理它们。因此,在命令行中,我们运行 artisan 的queue:listen命令,这将开始处理我们的队列。很快,我们可以进入我们的日志目录,看到从队列中发送的信息。

还有更多...

我们可能需要队列的原因有很多。最常见的是处理图像或进行大量数据解析等。将我们想要从网站发送的任何电子邮件排队也很有用,而 Laravel 有一种特殊的方法可以使用Mail::queue()命令来实现。

将 Laravel 应用程序部署到 Pagoda Box

Pagoda Box 是一个流行的云托管服务,可以很容易地创建 Web 应用程序。有了 Laravel 的预制框,我们可以在云中创建自己的网站。

准备工作

为了完成此操作,我们需要在 Pagoda Box 拥有一个免费帐户,可以在dashboard.pagodabox.com/account/register上获得。注册后,我们还需要在我们的帐户中添加一个 SSH 密钥。有关 SSH 密钥的更多信息,请访问help.pagodabox.com/customer/portal/articles/202068

如何做...

要完成此操作,请按照给定的步骤进行:

  1. 登录 Pagodabox 后,点击新应用程序选项卡,如下面的屏幕截图所示:如何做...

  2. 确保选择Quickstart,然后向下滚动找到 laravel-4 quickstart。然后点击免费按钮,如下面的屏幕截图所示:如何做...

  3. 在下一页中,点击启动按钮,如下面的屏幕截图所示:如何做...

  4. 等待几分钟,直到所有内容都安装完成。如何做...

  5. 完成后,点击蓝色的管理您的应用按钮,如下面的屏幕截图所示:如何做...

  6. 复制 git clone URL,如下面的屏幕截图所示:如何做...

  7. 在命令行窗口中,转到服务器的根目录并运行 git clone 命令。在我们的情况下,它将是:

**git clone git@git.pagodabox.com:erratic-eladia.git pagodaapp**

  1. 下载所有内容后,打开app/routes.php文件并添加一个路由,以便我们可以根据以下代码进行测试:
Route::get('cool', function()
{
  return 'Pagoda Box is awesome!';
});
  1. 在命令行窗口中,提交以下更改并将其发送回 Pagoda Box
 **git commit –am 'Added route'**
 **git push origin master**

  1. Pagoda Box 完成更改后,转到新路由查看是否有效。在我们的情况下,它将是erratic-eladia.gopagoda.com/cool

工作原理...

如果我们想要托管我们的应用程序并确保它是可扩展的,我们可能需要考虑使用云托管服务。这将使我们能够在出现大量流量时提高其性能,并在流量减少时降低性能。一个与 PHP 和 Laravel 兼容的优秀主机是 Pagoda Box。Pagoda Box 还有一个非常好的免费选项,可以让我们测试并创建一个完整的应用程序而无需付费。

首先,在 Pagoda Box 仪表板中,我们创建一个新应用程序并选择我们想要使用的 Quickstart 包。列表中有一个方便的 Laravel 4 安装;如果我们选择它,所有依赖项都将被安装。

设置完成后,我们可以复制 git clone 代码并将文件下载到本地服务器。下载后,我们可以进行任何更新并提交。将其推送回 Pagoda Box 后,我们的更新代码将自动部署,并且我们将在实时站点上看到更改。

还有更多...

还有其他与 Laravel 兼容的云托管提供商。它们通常都有免费选项,因此我们可以尝试它们。其他一些主机如下:

使用 Stripe 支付网关与 Laravel

电子商务网站是网站开发中的一个持续的重点。过去,诸如信用卡处理之类的事情一直很困难,学习曲线非常陡峭。使用 Laravel 和 Stripe 服务,提供信用卡交易变得更容易。

准备工作

对于这个食谱,我们需要一个正常安装的 Laravel 4 和 Stripe 的正确凭据。可以在stripe.com/创建一个免费的 Stripe 账户。

如何做...

要完成这个食谱,请按照以下步骤进行:

  1. 打开应用的composer.json文件,并更新require部分以类似以下代码片段的方式进行更新:
"require": {
  "laravel/framework": "4.0.*",
  "stripe/stripe-php": "dev-master"
},
  1. 在命令行窗口中,使用以下命令运行 composer update:
 **php composer.phar update**

  1. app/config目录中,创建一个名为stripe.php的新文件,使用以下代码:
<?php

return array(
  'key' => 'fakeKey-qWerTyuuIo4f5'
);
  1. routes.php文件中,添加一个Route到付款表单,如下所示的代码:
Route::get('pay', function()
{
  return View::make('pay');
});
  1. app/views文件夹中,使用以下代码片段创建一个名为pay.blade.php的文件,用于我们的表单:
{{ Form::open(array('url' => 'pay', 'method' => 'post')) }}
  Card Number: {{ Form::text('cc_number', 
    '4242424242424242') }}<br>

  Expiration (month):
    {{ Form::select('cc_exp_month', array(1 => '01', 2 => 
    '02', 3 => '03', 4 => '04', 5 => '05',6 => '06', 7 => 
    '07', 8 => '08', 9 => '09', 10 => '10', 11 
    => '11', 12 => '12')) }}<br>

  Expiration (year):
    {{ Form::select('cc_exp_year', array(2013 => 2013,
    2014 => 2014, 2015 => 2015, 2016 => 2016)) }}<br>

  {{ Form::submit('Charge $37 to my card') }}
  {{ Form::close() }}
  1. 回到routes.php,创建一个Route来接受表单提交,并按照以下代码对卡进行收费:
Route::post('pay', function()
{
  Stripe::setApiKey(Config::get('stripe.key'));
  $chargeCard = array(
    'number' => Input::get('cc_number'),
    'exp_month' => Input::get('cc_exp_month'),
    'exp_year'  => Input::get('cc_exp_year')
);
  $charge = Stripe_Charge::create(array('card' => 
    $chargeCard, 'amount' => 3700, 'currency' => 'usd'));

// Save returned info here
  var_dump($charge);
});

工作原理...

我们首先将 Stripe 包添加到我们的 composer 文件中并进行更新。这将安装 Stripe 代码,以及如果需要的话任何依赖项。然后我们需要创建一个配置文件来保存我们的 API 密钥。在这里,我们可以创建另一个与我们的环境变量相同的目录,并将文件添加到那里。因此,如果我们有一个开发和一个生产服务器,我们可以在app/config/development目录中有一个 Stripe config文件,其中保存我们的测试 API 密钥,然后在app/config/production目录中有一个文件来保存我们的生产 API 密钥。

接下来,我们需要一个表单,让用户输入他们的信用卡信息。我们创建一个pay路由来显示我们的pay视图。在该视图中,我们将使用 Blade 模板来创建表单。Stripe 所需的最少信息是卡号和到期日,尽管有时我们可能需要获取卡的 CVV 码或用户的地址。

在表单提交后,我们使用 API 密钥创建一个 Stripe 实例。然后我们将信用卡信息添加到一个数组中。最后,我们将金额(以美分为单位)、卡数组和货币发送到 Stripe 进行处理。

然后可以将从 Stripe 返回的数据添加到数据库中,或者进行其他跟踪。

还有更多...

Stripe 提供了许多易于使用的方法来管理信用卡交易,甚至订阅等事项。有关更多信息,请务必查看stripe.com/docs上提供的文档。

进行 GeoIP 查找和设置自定义路由

也许我们的应用程序在某些时候需要根据用户所在的国家/地区提供不同的页面。使用 Laravel 和 MaxMind 的 GeoIP 数据,我们可以根据用户的 IP 地址查找其所在的国家/地区,然后将其重定向到我们需要的页面。

准备工作

对于这个食谱,我们只需要一个正常的 Laravel 4 安装。

如何做...

要完成这个食谱,请按照以下步骤进行:

  1. 打开composer.json文件并更新require部分,使其看起来像以下代码片段:
"require": {
  "laravel/framework": "4.0.*",
  "geoip/geoip": "dev-master"
},
  1. 在命令行窗口中,使用以下命令运行 composer update:
 **php composer.phar update**

  1. 转到dev.maxmind.com/geoip/legacy/geolite/并下载最新的GeoLite Country数据库。解压缩并将GeoIP.dat文件放在我们应用的根目录中。

  2. app/config目录中,创建一个名为geoip.php的文件,使用以下代码:

<?php

return array(
  'path' => realpath("path/to/GeoIP.dat")
);
  1. 打开app/filters.php文件,并添加一个用于我们的geoip文件的过滤器,使用以下代码:
  Route::filter('geoip', function($route, $request, $value = NULL)
{
  $ip = is_null($value) ? Request::getClientIp() : $value;
  $gi = geoip_open(Config::get('geoip.path'), GEOIP_STANDARD);
  $code = geoip_country_code_by_addr($gi, $ip);
  return Redirect::to('geo/' . strtolower($code));
});
  1. 在我们的routes.php文件中,创建一个路由来应用过滤器,并创建一个接受国家代码的路由,如下所示的代码:
Route::get('geo', array('before' => 'geoip:80.24.24.24', function()
{
return '';
}));
Route::get('geo/{country_code}', function($country_code)
{
return 'Welcome! Your country code is: ' . $country_code;
});

工作原理...

我们首先通过将其添加到我们的composer.json文件并进行更新来安装geoip库。一旦下载完成,我们就可以下载 MaxMind 的免费geoip数据文件并将其添加到我们的应用程序中。在我们的情况下,我们将文件放在我们的应用程序的根目录中。然后,我们需要创建一个config文件,用于保存geoip数据文件的位置。

接下来,我们想要检查用户的 IP 地址并将他们重定向到特定国家的页面。为此,我们将使用 Laravel 的 before 过滤器。它从设置$ip变量开始。如果我们手动传递一个 IP 地址,那就是它将使用的;否则,我们运行Request::getClientIp()方法来尝试确定它。一旦我们有了 IP 地址,我们就通过geoip函数运行它来获取 IP 地址的国家代码。然后我们将用户重定向到带有国家代码作为参数的路由。

然后我们创建一个路由来添加过滤器。在我们的情况下,我们将手动传递一个 IP 地址给过滤器,但如果没有,它将尝试使用用户的地址。我们的下一个路由将以国家代码作为参数。在这一点上,我们可以根据国家提供自定义内容,甚至自动设置要使用的语言文件。

收集电子邮件地址并与第三方电子邮件服务一起使用

电子邮件列表和通讯简报仍然是与大量人群沟通的一种流行和高效的方式。在这个步骤中,我们将使用 Laravel 和免费的 MailChimp 服务来建立一个收集电子邮件订阅的简单方式。

准备工作

对于这个步骤,我们将需要一个可用的 Laravel 4 安装,以及在 Mailchimp 帐户部分生成的mailchimp.com/免费帐户和 API 密钥。我们还需要在 Mailchimp 中创建至少一个列表。

如何做...

要完成这个步骤,请按照以下步骤操作:

  1. app目录中,创建一个名为libraries的新目录。

  2. apidocs.mailchimp.com/api/downloads/#php下载 Mailchimp 的 API 库,然后解压缩并将文件MCAPI.class.php放入新的libraries文件夹中。

  3. 打开 Laravel 的composer.json文件,并将 libraries 目录添加到autoload部分。该部分应该类似于以下代码片段:

"autoload": {
    "classmap": [
    "app/commands",
    "app/controllers",
    "app/models",
    "app/database/migrations",
    "app/database/seeds",
    "app/tests/TestCase.php",
    "app/libraries"
]
},

  1. 打开命令行窗口,并运行 composer 的dump-autoload命令,如下所示:
 **php composer.phar dump-autoload**

  1. app/config目录中,创建一个名为mailchimp.php的文件,并使用以下代码:
<?php

return array(
  'key' => 'mykey12345abcde-us1',
  'list' => 'q1w2e3r4t5'
);
  1. 要获取我们的 Mailchimp 列表,并查看它们的 ID,请打开routes.php文件并添加一个新的路由,如下所示:
Route::get('lists', function()
{
  $mc = new MCAPI(Config::get('mailchimp.key'));
  $lists = $mc->lists();

  if($mc->errorCode) {
    echo 'Error loading list: ' . $mc->errorMessage;
  } else {
    echo '<h1>Lists and IDs</h1><h3>Total lists: '
    $lists['total'] . '</h3>';
  foreach($lists['data'] as $list) {
   echo '<strong>' . $list['name'] . ':</strong> ' .
   $list['id'] . '<br>';
}
}
});

  1. routes.php文件中,使用以下代码创建一个路由来显示subscribe表单:
Route::get('subscribe', function()
{
  return View::make('subscribe');
});
  1. app/views目录中,创建一个名为subscribe.blade.php的文件,如下所示:
  {{ Form::open() }}
  First Name: {{ Form::text('fname') }} <br>
  Last Name: {{ Form::text('lname') }} <br>
  Email: {{ Form::text('email') }} <br>
  {{ Form::submit() }}
  {{ Form::close() }}
  1. routes.php文件中,创建一个路由来接受和处理表单提交,如下所示:
Route::post('subscribe', function()
{
  $mc = new MCAPI(Config::get('mailchimp.key'));

  $merge_vars = array('FNAME' => Input::get('fname'), 'LNAME' => Input::get('lname'));
  $ret = $mc->listSubscribe(Config::get('mailchimp.list'), Input::get('email'), $merge_vars);

if ($mc->errorCode){
  return 'There was an error: ' . $mc->errorMessage;
} else {
  return 'Thank you for your subscription!';
}
});

它是如何工作的...

要开始这个步骤,我们需要添加 Mailchimp 的 PHP 库。由于我们不会使用 composer,我们需要设置一个目录来保存我们的非 composer 库。因此,我们在app文件夹中创建一个libraries目录,并在其中添加 Mailchimp。

为了让 Laravel 知道我们想要在新目录中autoload任何内容,我们需要更新composer.json文件。然后我们将目录位置添加到Classmap部分。然后我们需要运行 composer 的dump-autoload命令来重新创建我们的autload文件,并将其添加到我们的新目录中。

然后我们需要创建一个新的config文件来保存我们的 Mailchimp 凭据和我们想要使用的列表的 ID。我们可以从 Mailchimp 仪表板获取list ID,或者我们可以使用lists路由来显示它们。

为了捕获用户的电子邮件,我们创建一个路由和视图来保存我们的表单。这个表单也可以是一个弹出窗口、模态框或更大页面的一部分。我们要求他们的姓名和电子邮件,然后将其发布到 Mailchimp。

在我们的post路由中,我们只需要实例化 Mailchimp 类,创建一个数组来保存名称,并将所有内容发送到listSubscribe()方法。最后,我们检查来自 Mailchimp 的任何错误并显示成功消息。

还有更多...

Mailchimp 提供了一个非常广泛的 API,允许我们轻松管理我们的电子邮件列表。要查看他们提供的所有内容,请查看在线文档:apidocs.mailchimp.com/

从亚马逊 S3 存储和检索云内容

使用像亚马逊的 S3 这样的服务来存储我们的文件将使我们能够利用他们服务器的速度和可靠性。要使用该服务,我们可以轻松地实现一个 Laravel 包来处理我们上传到亚马逊的文件。

准备工作

对于这个食谱,我们需要一个可用的 Laravel 4 安装。我们还需要一个免费的亚马逊 AWS 账户,可以在以下网址注册:aws.amazon.com/s3/

注册后,我们需要从“安全凭据”页面获取我们的访问密钥 ID秘密 ID。此外,在 S3 管理控制台中,我们需要至少创建一个存储桶。对于这个食谱,我们将把存储桶命名为laravelcookbook

如何做…

完成这个食谱,按照给定的步骤进行:

  1. 打开 Laravel 的composer.json文件并添加亚马逊 SDK 包。要求部分应该类似于以下片段:
"require": {
  "laravel/framework": "4.0.*",
  "aws/aws-sdk-php-laravel": "dev-master"
},
  1. 打开命令行窗口,并使用 Composer 包安装包,如下所示:
 **php composer.phar update**

  1. 安装完成后,在app/config目录中,创建一个名为aws.php的文件,如下所示:
<?php

return array(
  'key'    => 'MYKEY12345',
  'secret' => 'aLongS3cretK3y1234abcdef',
  'region' => '',
);
  1. app/config目录中,打开app.php文件。在providers数组的末尾,按照以下代码添加 AWS 提供程序:
  'Aws\Laravel\AwsServiceProvider',
  1. 还在app.php文件中,在别名数组中,添加以下别名:
  'AWS' => 'Aws\Laravel\AwsFacade',
  1. 在我们的routes.php文件中,通过创建一个列出我们的buckets的路由来测试一切是否正常,如下所示:
Route::get('buckets', function()
{
  $list = AWS::get('s3')->listBuckets();
    foreach ($list['Buckets'] as $bucket) {
    echo $bucket['Name'] . '<br>';
}
});

  1. 要测试存储桶,请转到http://{your-server}/buckets,它应该显示我们设置的所有存储桶的列表。

  2. 现在让我们创建一个用户上传图像的表单。我们首先创建一个包含表单的路由,如下所示:

Route::get('cloud', function()
{
  return View::make('cloud');
});
  1. app/views文件夹中,创建一个名为cloud.blade.php的文件,其中包含以下代码:
  {{ Form::open(array('files' => true)) }}
  Image: {{ Form::file('my_image') }} <br>
  {{ Form::submit() }}
  {{ Form::close() }}
  1. 回到routes.php文件,在下面的代码中创建一个路由来处理文件并将其上传到 S3:
Route::post('cloud', function()
{
  $my_image = Input::file('my_image');
  $s3_name = date('Ymdhis') . '-' . $my_image
    >getClientOriginalName();
  $path = $my_image->getRealPath();

  $s3 = AWS::get('s3');
  $obj = array(
    'Bucket'     => 'laravelcookbook',
    'Key'        => $s3_name,
    'SourceFile' => $path,
    'ACL'        => 'public-read',
);

  if ($s3->putObject($obj)) {
  return
    Redirect::to('https://s3.amazonaws.com/laravelcookbook/
    ' . $s3_name);
} else {
  return 'There was an S3 error';
}
});

它是如何工作的…

我们首先通过安装亚马逊的 AWS SDK 来开始这个食谱。幸运的是,亚马逊发布了一个专门为 Laravel 4 设计的 composer 包,所以我们只需将其添加到我们的composer.json文件中并进行更新。

安装完成后,我们需要创建一个配置文件并添加我们的亚马逊凭据。我们还可以添加region(例如Aws\Common\Enum\Region::US_WEST_2),但是,如果我们将其留空,它将使用US Standard区域。然后我们更新我们的app.php配置,包括亚马逊提供的 AWS ServiceProviderFacade

如果我们已经在 S3 中有存储桶,我们可以创建一个路由来列出这些存储桶。它通过创建一个新的 S3 实例并简单调用listBuckets()方法开始。然后我们循环遍历Buckets数组并显示它们的名称。

我们的下一个目标是创建一个表单,用户可以在其中添加图像。我们创建一个名为cloud的路由,显示cloud视图。我们的视图是一个简单的 Blade 模板表单,只有一个file字段。然后该表单将被提交到cloud

在我们的cloud post 路由中,我们首先使用Input::file()方法检索图像。接下来,我们通过在文件名的开头添加日期来为我们的图像创建一个新名称。然后我们获取上传图像的路径,这样我们就知道要发送到 S3 的文件是哪个。

接下来,我们创建一个 S3 实例。我们还需要一个数组来保存要发送到 S3 的值。Bucket只是我们想要使用的 S3 存储桶的名称,Key是我们想要给文件的名称,SourceFile是我们想要发送的文件的位置,然后ACL是我们想要给文件的权限。在我们的情况下,我们将ACL设置为public-read,这允许任何人查看图像。

我们的最后一步是调用putObject()方法,这应该将所有内容发送到我们的 S3 存储桶。如果成功,我们将重定向用户查看已上传的文件。

还有更多...

在我们的示例中,用户被迫等待图像上传到亚马逊之前才能继续。这将是一个使用队列处理一切的绝佳案例。

参见

  • 创建队列并使用 Artisan 运行它的配方
posted @ 2024-05-05 00:11  绝不原创的飞龙  阅读(31)  评论(0编辑  收藏  举报