Laravel教程 四:数据库和Eloquent

JellyBool

JellyBool

上一篇写了一些Laravel Blade的基本用法和给视图传递变量的几种方式,

这一节我们来说说跟数据库打交道的数据库配置和Laravel强大的Eloquent。

Laravel的数据库配置

本部分内容为下节做准备

Laravel的配置文件都是在项目目录的config/文件夹之下,这里也就是在blog/config文件夹之下,你可以打开这个文件夹看看,你面有很多配置文件:如mail.php(配置邮件发送服务的)database.php(配置数据库的),我们这里就是来看看这个database.php配置文件:


 'connections' => [

        'mysql' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST', 'localhost'),
            'database'  => env('DB_DATABASE', 'forge'),
            'username'  => env('DB_USERNAME', 'forge'),
            'password'  => env('DB_PASSWORD', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ]

        //...
        ]

打开文件,你可以看到里面只是返回简单地php数组而已,我们目前只是关心connections这个数组。上面的代码并没给出所有的数据库配置,你可以自己看,由于博主使用的是mysql,所以这里会给出mysql的配置,其他数据库你可以参照着来,后续的教材博主也会依旧使用mysql。

那这里说到的配置,基本上就是对下面四个变量的配置:

'host'      => env('DB_HOST', 'localhost'),
//如果.env文件没有DB_HOST配置,则取localhost,后面的一样
'database'  => env('DB_DATABASE', 'forge'),
'username'  => env('DB_USERNAME', 'forge'),
'password'  => env('DB_PASSWORD', ''),

这里的env()方法是读取到.env (位于blog/.env) 这个文件里面的配置项

替代文字

打开这个文件,你可以看到一些常用的配置,包括debug模式和开发环境,你也可以看到我们下面这几个需要操作的选项:

DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

由于这里我使用的是Homestead的开发环境,所以才有了上面的配置(Homestead的默认用户名和密码为homestead和secret),如果你是直接使用php artisan serve这种方式开启服务来开发的话,相应地修改你的配置。

Laravel为什么要采取这样的配置呢?很大的一个原因可能就是考虑到文件的安全性和便捷性,这样我们在需要将代码推送到coding或者Github的时候,我们可以直接ignore这个.env文件,不必担心我们的核心信息呗泄露。在部署应用的时候,我们可以直接在服务器创建一个.env文件,写上对应的配置项就OK了。

就这样,只要我们正确配置信息,我们就连接上数据库了,当然,你得首先创建一个homestead数据库。

使用Migration

连接好数据库之后,我们就需要创建相对应的数据表了,在没有使用Laravel之前,你可能都是直接手动创建数据表的,比如我们这个blog项目,你会到数据库中手动创建一个articles数据表,但是在Laravel的项目中,我极力推荐你使用Migration,这样有什么好处呢?其实你可以将Migration看做一个数据库的版本管理工具,就如git对于我们的项目文件的版本管理,你可以rollback,你可以reset等,它给予你一种代码实现和命令行结合的方式来管理你的数据库,如果你在blog/目录下,命令行执行 php artisan ,你可以看到很多命令行,下面这几个就是我们这里谈到的rollbackreset等:

替代文字

红色框框这几个基本就是比较常用的,如果这里我还没有说服使用migration,那么我们来将这个过程走一遍:

首先,我们创建一个migration文件,也就是定义一张表的schema,命令行执行:

php artisan make:migration create_articles_table --create='articles'

替代文字

顺利执行之后,我们会得到一个migration文件,这个文件位于database/migrations/下面,打开这个文件夹,你可以看到Laravel本来就有两个migration文件,users表和password-reset表,我们在这个项目中目前还不用这两个文件。所以可以直接删掉,然后打开我们刚刚生成的migration文件:create_articles_table这个文件

 public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

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

这里有两个方法:up()down()up()方法是执行php artisan migrate的时候调用的,这个方法会创建一个articles数据表,而down()方法则是在php artisan migrate:rollback的使用执行的,这里会直接删除articles这个数据表。

但是,这里先不要急着执行php artisan migrate,我们还需要为articles的增加几个字段:

public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');// 主键 自增
            $table->string('title');
            $table->text('intro');
            $table->text('content');
            $table->timestamp('published_at');
            $table->timestamps(); // 自动创建的两个字段:created_at 和 updated_at
        });
    }

这里我们的intro字段是文章的简介,published_at字段是文章的发表日期,这样做对我们写博客有很大的好处,你可以将博客的发表日期控制起来,因为有一些我写好的但是还没有到发表日期的,还不想让用户看到的文章我就可以用published_at来控制了。这样之后,我们来执行一下php artisan migrate

替代文字

然后,articles这个表就创建成功了。

替代文字

这个时候你可能还没有体会到migration的好处,想象下面两个场景:


1. 在进行团队开发的时候,团队成员将我们的代码pull下来之后,怎么可以拿到一样的数据库表设计呢?难道要我们将表 export 出来,给每一个成员import一次?这显然不够明智,如果使用的migration,就一行命令,直接`php artisan migrate`,就可以拿到一样的数据库表了。

2. 如果这个时候我们发现articles这个表的有一个字段写错了,比如我们的intro字段写错,它应该命名为introduction的,这个时候,我们怎么办?直接手动改数据库的表?那么回到第一个场景,你的团队成员也需要手动改?这显然也不是我们喜欢的方式,这个时候,migration的优势就来了

比如我们这里演示一下怎么解决第二个场景:

我们只需要命令行执行:

php artisan migrate:rollback

替代文字

然后修改up()方法的intro字段:

$table->text('introduction');

然后再执行php artisan migrate

替代文字

大工告成,更多特性请看文档:

http://laravel.com/docs/5.1/migrations

使用Eloquent

上面我们创建好了articles数据表之后,我们就可以为这个表写一个Model类了,你可以手动创建,也可以使用artisan命令行来创建一个model,比如你在命令行敲php artisan,你会看到make下面会有很多命令,而make:model就是我们需要使用的命令:

替代文字

就像解释的一样:Create a new Eloquent model class

很多时候,在Laravel中,我们在创建一个model的时候都会有一些约定俗成的命名方法:

如果说我们有一个articles数据表,我们的model相对应就命名为Article;

如果说我们有一个users的数据表,我们的model对应就命名为User;

就是基本上遵守数据表复数而model单数大写就可以了。

所以根据这个规律我们来创建我们的Article Model,使用的是make:model命令:

php artisan make:model Article
 

替代文字

这样一来,我们的Article Model就创建成功了,这个文件位于blog/app/Article.php,打开之,可以看到我们Laravel为我们生成的内容:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    //
}

注意到Article这个类是继承与我们的Eloquent\Model 类,由于这个Eloquent\Model类实现了很多非常棒的方法供我们使用,我们可以来愉快地玩耍了。

首先开始玩耍的是,使用 php artisan tinker这个工具来play around,tinker提供了一个Eloquent跟数据库表交互的命令行界面,你可以在上面写一些简单地php操作,比如:

替代文字

所以,我们来实例化一个Article吧:

$article = new App\Article

替代文字

这样就相当于我们实例化了一个Article类了,我们可以在后面的操作中进行字段具体化。

在上面我们创建表的时候,我们有以下几个字段:

$table->increments('id');
$table->string('title');
$table->text('intro');
$table->text('content');
$table->timestamp('published_at');
$table->timestamps();

于是我们可以用tinker来设置以下上面的$article的各个字段,就如设置属性一样简单。

比如设置$articletitle可以这样:

$article->title = 'Router Views Controllers';

替代文字

同理,我们也可以将introcontent字段设置:

$article->intro = 'Article 1 Intro';
$article->content = 'Article 1 Content';

不过这里需要注意的是published_at这个字段,这里我推荐使用一个很棒的时间处理库Carbon,因为像created_atupdated_at这两个字段也是使用的Carbon类,这样在后面的处理中,我们会有很多好处,这里我们先直接使用Carbon:

$article->published_at = Carbon\Carbon::now();

替代文字

而对于$table->timestamps()这个,Laravel会在我们插入数据的时候自动完成的,所以这里我们每个字段都赋值完毕之后,我们可以使用Eloquentsave()方法来向数据库的articles表插入一条数据了:

$article->save();

替代文字

返回一个true的时候,表示我们成功插入数据了,我们来看看数据库:

替代文字

以上,就是一个简单而完整的使用tinker给Eloquent赋值的玩耍过程。

下面我们再来玩耍一会:

all()方法

all()方法会返回Article的所有记录:

$articles = App\Article::all();

替代文字

find(),接受一个参数$id,比如查找id为1的一条记录:

$article = App\Article::find(1);

你也可以传入一个$id的数组,查找多条记录,不过这里我们只有一条数据,所以就这样了。不过我们也可以这样玩玩:

toArray()方法:

将一个Eloquent的对象转为数组:

$article = App\Article::find(1)->toArray();

替代文字

toJson()方法

将一个Eloquent的对象转为json字串:

$article = App\Article::find(1)->toJson();

替代文字

如果就简简单单这样的话,Eloquent也不能算很强大,我们在写代码过程中的where语句呢,这个也没有么?

不用担心,这个马上就有:

where()方法

$article = App\Article::where('title','=','Router Views Controllers')->get();

替代文字

在使用where()的时候,往往需要用get()来获取记录集,这个返回的是一个Eloquent\Collection结果集,但是如果我就是想要满足条件的第一天记录呢,不需要结果集呢?

使用first()方法,在上面的基础上,get()换成first()

$article = App\Article::where('title','=','Router Views Controllers')->first();

替代文字

到这里,一些简单地查找工作就可以告一段落了,而对于update呢,我们可以这样:

$article = App\Article::find(1);
$article->intro = 'Article 1 Intro Update!';
$article->save();

替代文字

我们来看看有没有更新:

$article = App\Article::find(1);

替代文字

也可以使用update()方法:

$article->update(['content'=>'Article 1 Content Update']);

正常情况下我们会得到一个MassAssignmentException with message

替代文字

文档看这里: http://laravel.com/docs/5.1/eloquent#mass-assignment

这个是因为Eloquent默认是不允许我们直接更新我们的数据的,这是出于可能出现数据覆盖的情况,但是如果我们确实是先要实现这样的功能,我们可以在Article这个model文件里面加一个$fillable数组:

class Article extends Model
{
    protected $fillable = ['content'];
}

然后再执行一次看看:

替代文字

这里需要Ctrl + C 退出tinker在重新进来一次。

查找,更新之后,借着我们在聊到MassAssignment这个概念的时候,我们可以来聊聊create()这个方法了,这个方法可以在不用声明new Article()的情况下创建一条数据,比如:

 App\Article::create(['title'=>'Article 2','intro'=>'intro 2','content'=>'Article 2 content','published_at'=>Carbon\Carbon::now()]);

然后我们会看到一个奇怪的现象,我们并没有得到我们想要的结果:

替代文字

我们只有content这个字段正确有了值,titleintropublished_at都没有值,这是为什么了?其实也是因为MassAssignment的缘故,我们可以参照content的时候,在Article里面的$fillable设置我们的可以填充的字段:

class Article extends Model
{
    protected $fillable = [
        'title',
        'intro',
        'content',
        'published_at'
    ];
}

然后再执行一次:

替代文字

成功创建了一条数据,然后我们发现第二条其实并不是我们想要的,我们来删除它:

使用delete()方法:

$article = App\Article::find(2);
$article->delete();

替代文字

我们用all()来检查一下:

替代文字

这里也可以使用destroy(),这个方法可以接受一个$id或者一个数组$ids:

App\Article::destroy(3);

替代文字

最后还是放一下官方文档:http://laravel.com/docs/5.1/eloquent

下一节

到这里基本的Eloquent也就介绍到这里了,鉴于这一节说了Model,前面也都接触过Views和Controllers,下一节打算说说Model Views Controllers的基本流程。

Happy Hacking

本文由 JellyBool 创作, 转载和引用遵循 署名-非商业性使用 2.5 中国大陆 进行许可。

共有 96 条评论

LDL

感觉那个 thinker 不好用,没自动补全,假如对一个没有数据库表里面没有的字段赋值,还要退出重新敲一次

JellyBool

额,好的吧,习惯了就好其实。这种交互界面实在很高效,习惯的话。就像在写Python时候一样 @LDL

LDL

@JellyBool 你有用过Lumen开发移动app服务端api吗?

JellyBool

还没有试过 @LDL

woailuosj

假如对一个没有数据库表里面没有的字段赋值,一定要退出重新敲一次啊?还想问有什么办法没

haoran

我想问下如何输入中文啊?敲不进去啊

elick

博主 我再windows下使用这句
php artisan make:migration create_articles_table --create=‘articles’
生成的文件 Schema::create(’‘articles’’, function (Blueprint $table){ 会多出个引号来 生成数据库就会报错
这里希望给大家一个提示

hehorange 回复 elick

我也补充一下
生成文件的 down() 方法中也会多出一个引号
Schema::drop(' 'articles' ')
同样在生成数据表是报语法错误

dudushuang

看到课程四,我想到了express和python。总有那么一点儿似曾相识。。。。。。。

xuan2429833524

表没有存到数据库,请问是什么问题

JellyBool

图片不是有提示么? 使用migrate啊 @xuan2429833524

xuan2429833524

请问数据表的字段类型在哪里可以查到
就是字符类型string是表示varchar还是char
数值类型用什么表示
长度是如何设置呢

HappytreeFriends

请问where()方法如果是多条件判断怎么办呢?

ksir

@JellyBool 请问save()和update()有什么区别吗?

Anonymous

哦莫 我的沙发

Anonymous

https有灰色的锁是因为这个多说评论框?

Anonymous

感谢感谢。。。多来光顾

Anonymous

还是延长了半个小时。。准备睡觉

Anonymous

对。。因为多说得头像直接使用的是微博或者qq等其他第三方的头像链接,这些链接并不是https源,所以chrome会觉得这不够安全

Anonymous

Hello jelly,我刚刚接触Laravel,有个数据库连接的问题请教:
我用的是阿里云的PostgreSQL,阿里云提供的端口号最大只能设置到3999,而postgres默认是5432,查文档Laravel默认也是使用5432,我想问问怎么修改端口号是正确的姿势。。。
我修改的配置信息包括:
database.php里default的连接信息为‘pgsql’
connection里的host、dbname、dbuser、dbpassword
.env文件里同样4个参数
在connection里加了一个’port’=3999
在.env里加了一个DB_PORT

以上信息都修改完成后运行php artisan migrate报错:
[InvalidArgumentException] Database [postgres] not configured.

已经确认了好几遍数据库信息都是对的,都是从后台copy下来的。。。求解,谢谢~~

Anonymous

不好意思,default里设置的是postgres,如果设置pgsql会报错为[PDOException]
could not find driver

Anonymous

首先确认一下你的这两个文件:

/etc/php.d/pdo.ini 和 /etc/php.d/pgsql.ini ,有没有成功加载PDO driver for pg

Anonymous

还是不行的话,你用一下这个packages : composer require doctrine/dbal

Anonymous

pgsql.so 和 pdo_pgsql.so两个都加载了,在phpinfo里都看得到,我去尝试下package的方法看看,thx

Anonymous

OK,最后看看能不能解决

Anonymous

五什么时候更新?

Anonymous

我这两天部署完我新写的项目就可以了

Anonymous

期待下一节,很有帮助,谢谢!

Anonymous

谢谢,我近期就更新,这两天就好了

Anonymous

基本确认问题在哪里了……服务器加载的php.ini和浏览器加载的php.ini不是一个文件,浏览器phpinfo看到的.so文件在实际laravel环境下并没有加载成功。服务器上输入php --ini,显示
Configuration File (php.ini) Path: /etc/php5/cli
Loaded Configuration File: /etc/php5/cli/php.ini
我浏览器phpinfo出来的在/usr/local下……
头大了

Anonymous

那问题解决了没有

Anonymous

已经解决了!!!豁然开朗啊真是!
在这顺便提供下解决办法:
连接pgsql的各项设置都是对的,default的CONNECTION要设置为‘pgsql’
驱动无法加载问题是因为PHP的CLI模式和普通模式执行的php.ini文件不一致。CLI模式加载的是php --ini的那个,用ln -s把cli追踪到的最终一个文件的源文件设置成和phpinfo现实的为同一个php.ini,再执行migrate就成功了

Anonymous

OK,解决了就好。。。

Anonymous

期待ing

Anonymous

真的很感谢,我今晚来写吧

Anonymous

赶快赶快!今晚写两节。

Anonymous

写的挺不错的,比较清晰。

Anonymous

这个实在是很难啊,事情有点多。。。

Anonymous

感谢感谢,常来看看

Anonymous

第五篇已出。。。就在下一篇

Anonymous

第五篇已出

Anonymous

第五篇已出

Anonymous

第五篇已出,只写了一篇。。晚上再写一篇吧

Anonymous

顶一个 LZ blog做一个分享页面吧 可以分享到微博什么的

Anonymous

真的有需要么?写一个应该很简单

Anonymous

直接用了多说的分享插件。。。Happy Hacking

Anonymous

很喜欢楼主的blog风格。简约美,不知道是否有开源的打算

Anonymous

又是问我开源。。。这个无所谓,当时放过到coding上面,后面整理一下代码再开源出来吧

Anonymous

32个赞 [good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good][good]

Anonymous

哈哈哈,这没什么啊

Anonymous

写的非常好!

Anonymous

谢谢,常来看看就行了

Anonymous

谢谢,常来看看就行了

Anonymous

谢谢分享, 写的很细 ,适合我这样的新手 , 不然从别的地方随便抄抄根本理解不了其中的原理 , 以至于坚持一段时间就觉得枯燥放弃了 , 这样理解之后会发现其中的妙处 , 会一直追下去的 .[给力]

Anonymous

谢谢,常来看看

Anonymous

回滚后修改字段,不是把表删了,那我之前的测试数据不是都没了

Anonymous

这种情况下创建一个新的migration 文件,使用$table->renameColumn(‘from’, ‘to’);

Anonymous

好的,谢谢

Anonymous

没事,有啥laravel相关的问题,可以到这里来看看

https://laravist.com/

Anonymous

hi,Jelly,这两天在学习php和laravel,有个东西很疑惑,env(‘DB_HOST’, ‘localhost’),这个是说没有env的话,就会去使用默认值,然后我进入env这个方法,实际调用的是value=getenv(value = getenv(key);,进入getenv,发现function getenv ($varname) {},这个是一个空方法,但是我debug发现他取到了值,我就很疑惑了,空方法也能放回正确的东西吗?还是做他有子类去实现了他?

Anonymous

原生函数,我可以看到源代码吗?或者说,这个是不是类似java里面的native方法,就不能查看源代码了?

Anonymous

简单的说就是php内置的吧,可以在php.net看到有文档解释。。。不知道这样说有问题不。

Anonymous

博主的文章写的很详细,通熟易懂,逻辑性很好,比官方文档好多了。博主要继续更新啊。期待。。。

Anonymous

额,现在跑去录视频了

Anonymous

真是人才。[good]

Anonymous

额。。。谢谢

Anonymous

php artisan tinker ,感觉没什么用,还不如直接在数据库里面操作来的方便来得快

Anonymous

看个人喜好呗

Anonymous

请问博主,使用php artisan可以直接删除Model吗?

Anonymous

直接删除那个文件就行

Anonymous

作为一名想学laravel的学生, 博主的教程很赞

一心为谁

你好,使用tinker 我遇到一个问题:在创建了 Aritcle 类后,使用php artisan tinker 进入命令行交互界面,
然后实例化 $article=new App\Article 报错:“PHP Fatal error: Class ‘App\Article’ not found in eval()'d code in line 1”, 这是怎么回事?

yangju15 回复 一心为谁

我也是遇到了这个问题,不知道怎么回事

JellyBool 回复 一心为谁

估计命名空间没写对,或者php的版本太低

AyeG

sequel pro的配置是什么样子的,为什么我一直连接不上

JellyBool 回复 AyeG

你连的是 homestead?注意端口 33060

zionhuang

博主你好,关于update这个,我已经加了fillable,但还是更新不了,是新版本作了了调整还是?

JellyBool 回复 zionhuang

需要退出 tinker ,再进去

zionhuang 回复 JellyBool

对,是这样的,我当天关掉去睡觉,第二天再用的时候就可以update了,不过还是谢谢博主的解答。然后我发现在后面的步骤中,在create和store的时候,总是失败,我试着加了guard=[]之后终于可以新建文章了,不知道是我看漏了还是博主没写仔细,在这里补充一下。

duo

$article->update([‘id’=>’2’]);
PHP error: Use of undefined constant ’2’ - assumed ‘’2’’ on line 1
这个错误怎么解决啊?

duo

$article->update([‘content’=>“更新文章内容”]);
明白了用双引号

jimone

文章图片都不显示了~