Laravel教程十四 Eloquent关系

Eloquent关系基本可以分为:一对一、一对多及多对多。比如我们一个用户可以发表多篇文章,就是一对多的关系。这一节就是介绍 Laravel 5 中的Eloquent关系。

打开 app\User.php 用户模型,在 User 类中添加如下代码:

    public function articles(){
        return $this->hasMany('App\Article');
    }

这样就可以通过 $user->articles 来获取用户的所有文章了。现在来实现通过 $article->user 来获取文章所属的用户,打开 app\Article.php,在 Article 类中添加:

    public function user(){
        return $this->belongsTo('App\User');
    }

其中方法 user() 的名称可以自己随便定义,比如还可以叫 owner() 或者 writer() 等等。

现在还需要考虑我们的表结构,我们在表中还没有涉及到文章与用户的关联关系。现在打开之前我们创建的 migrations 文件 database\migrations\***_create_articles_table.php ,修改其中的 up() 方法:

    public function up()
    {
        Schema::create('articles', function(Blueprint $table)
        {
            $table->increments('id');
            // 指定文章所属用户ID
            $table->integer('user_id')->unsigned();
            $table->string('title');
            $table->text('body');
            $table->timestamps();
            $table->timestamp('published_at');
 
            // 生成外键,并且指定在删除用户时同时删除该用户的所有文章
            $table->foreign('user_id')
                ->references('id')
                ->on('users')
                ->onDelete('cascade');
        });
    }

上面的方法中,添加了指定文章所属用户的字段 user_id ,指定其为用户表 users 的外键,并且当用户表中该用户被删除的时候,同时删除该用户的所有文章。

因为是本地开发环境,所以我们直接执行回滚操作,更新数据表结构。切记在线上的环境一定不要这么做,可以创建一个新的 migration 来完成该操作。
在命令行执行下面的命令:

D:\wamp\www\laravel5>php artisan migrate:refresh
 
Rolled back: 2015_05_11_142009_add_excerpt_to_articles_table
Rolled back: 2015_05_11_140813_create_articles_table
Rolled back: 2014_10_12_100000_create_password_resets_table
Rolled back: 2014_10_12_000000_create_users_table
Nothing to rollback.
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrated: 2015_05_11_140813_create_articles_table
Migrated: 2015_05_11_142009_add_excerpt_to_articles_table

现在来创建用户,虽然Laravel 5为我们提供了一套现成的用户系统,但是我们这里还是使用命令行 tinker 来完成。

D:\wamp\www\laravel5>php artisan tinker
Psy Shell v0.4.1 (PHP 5.5.12 ΓÇö cli) by Justin Hileman
>>> $user = new App\User;
=> <App\User #000000003bd871c8000000000acd1f5b> {}
>>> $user->name = 'Specs';
=> "Specs"
>>> $user->email = 'specs@example.com';
=> "specs@example.com"
>>> $user->password = bcrypt('password');
=> "$2y$10$psEuDj9D81ZnNs083E7W9.SqvcEuLoAk4V5NuuDPC/xc.fU.1NMFq"
>>> $user->save();
=> true
>>> App\User::first()->toArray();
=> [
       "id"         => 1,
       "name"       => "Specs",
       "email"      => "specs@example.com",
       "created_at" => "2015-06-07 12:41:37",
       "updated_at" => "2015-06-07 12:41:37"
   ]

用户密码必须要进行加密操作,bcrypt() 方法也可以用 Hash::make() 来替代。现成已经成功创建了一个新的用户。

现在来完成添加文章时与用户的关联操作。我们可以在控制器的 store() 方法中实现,但是现在我们先直接通过表单的一个隐藏域来完成,这样做是不安全的,实际环境中不可以使用该方法,下一节再来修复此问题。

打开 resources\views\articles\_form.blade.php ,在最上面添加:

{!! Form::hidden('user_id', 1) !!}

接着修改文章模型 Article.php,修改可填充字段:

    protected $fillable = [
        'title',
        'body',
        'published_at',
        'user_id'
    ];

这时浏览器中发布一篇新的文章试试。发布之后到命令行执行:

D:\wamp\www\laravel5>php artisan tinker
Psy Shell v0.4.1 (PHP 5.5.12 ΓÇö cli) by Justin Hileman
>>> App\Article::first()->toArray();
=> [
       "id"           => 1,
       "user_id"      => 1,
       "title"        => "New Article",
       "body"         => "This is a new article",
       "created_at"   => "2015-06-07 12:52:02",
       "updated_at"   => "2015-06-07 12:52:02",
       "published_at" => "2015-06-07 00:00:00",
       "excerpt"      => null
   ]
 
// 获取第一个用户所有文章
>>> $user = App\User::first();
=> <App\User #0000000070d8f2d5000000001310ee1c> {
       id: 1,
       name: "Specs",
       email: "specs@example.com",
       created_at: "2015-06-07 12:41:37",
       updated_at: "2015-06-07 12:41:37"
   }
>>> $user->articles->toArray();
=> [
       [
           "id"           => 1,
           "user_id"      => 1,
           "title"        => "New Article",
           "body"         => "This is a new article",
           "created_at"   => "2015-06-07 12:52:02",
           "updated_at"   => "2015-06-07 12:52:02",
           "published_at" => "2015-06-07 00:00:00",
           "excerpt"      => null
       ]
   ]

此外:

>>> $user->articles();
// 返回一个一对多的Object
=> <Illuminate\Database\Eloquent\Relations\HasMany #0000000070d8f2ca000000001310ee1c> {}
>>> $user->articles->toArray();
// 返回的是一个 collection
=> [
       [
           "id"           => 1,
           "user_id"      => 1,
           "title"        => "New Article",
           "body"         => "This is a new article",
           "created_at"   => "2015-06-07 12:52:02",
           "updated_at"   => "2015-06-07 12:52:02",
           "published_at" => "2015-06-07 00:00:00",
           "excerpt"      => null
       ]
   ]
//注意 使用 $user->articles 与 $user->articles() 的区别
>>> $user->articles()->get()->toArray();
=> [
       [
           "id"           => 1,
           "user_id"      => 1,
           "title"        => "New Article",
           "body"         => "This is a new article",
           "created_at"   => "2015-06-07 12:52:02",
           "updated_at"   => "2015-06-07 12:52:02",
           "published_at" => "2015-06-07 00:00:00",
           "excerpt"      => null
       ]
   ]
// $user->articles() 可以添加查询条件,而$user->articles 则不能这么使用
>>> $user->articles()->where('title', 'New Article')->get()->toArray();
=> [
       [
           "id"           => 1,
           "user_id"      => 1,
           "title"        => "New Article",
           "body"         => "This is a new article",
           "created_at"   => "2015-06-07 12:52:02",
           "updated_at"   => "2015-06-07 12:52:02",
           "published_at" => "2015-06-07 00:00:00",
           "excerpt"      => null
       ]
   ]

上面通过用户获取了用户的所有文章,下面我们完成相反的操作,根据文章来获取用户信息。

>>> $article = App\Article::first();
=> <App\Article #0000000073aaf26b000000001e78f0ec> {
       id: 1,
       user_id: 1,
       title: "New Article",
       body: "This is a new article",
       created_at: "2015-06-07 12:52:02",
       updated_at: "2015-06-07 12:52:02",
       published_at: "2015-06-07 00:00:00",
       excerpt: null
   }
>>> $article->user->toArray();
=> [
     

Laravel教程十四 Eloquent关系:等您坐沙发呢!

发表评论

表情
还能输入210个字