收货地址是电商网站必须功能,本次需要实现收货地址列表的展示。
首先,需要整理好 user_addresses
表的字段名称和类型:
字段和名称 | 描述 | 类型 | 加索引缘由 |
---|---|---|---|
id | 自增长ID | unsigned int | 主键 |
user_id | 该地址所属的用户 | unsigned int | 外键 |
province | 省 | varchar | 无 |
city | 市 | varchar | 无 |
district | 区 | varchar | 无 |
address | 具体地址 | varchar | 无 |
zip | 邮编 | unsigned int | 无 |
contact_name | 联系人姓名 | varchar | 无 |
contact_phone | 联系人电话 | varchar | 无 |
last_used_at | 最后一次使用时间 | datetime null | 无 |
通过 make:model
创建新模型:
$ php artisan make:model Models/UserAddress -fm
-fm
参数代表同时生成 factory
工厂文件和 migration
数据库迁移文件
根据上面整理出来的字段编写迁移文件:
_database/migrations/< your_date >create_user_addresses_table.php
.
.
.
public function up()
{
Schema::create('user_addresses', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->string('province');
$table->string('city');
$table->string('district');
$table->string('address');
$table->unsignedInteger('zip');
$table->string('contact_name');
$table->string('contact_phone');
$table->dateTime('last_used_at')->nullable();
$table->timestamps();
});
}
.
.
.
然后修改模型文件:
app/Models/UserAddress.php
.
.
.
protected $fillable = [
'province',
'city',
'district',
'address',
'zip',
'contact_name',
'contact_phone',
'last_used_at',
];
protected $dates = ['last_used_at'];
public function user()
{
return $this->belongsTo(User::class);
}
public function getFullAddressAttribute()
{
return "{$this->province}{$this->city}{$this->district}{$this->address}";
}
.
.
.
代码解析:
protected $dates = ['last_used_at'];
表示 last_used_at
字段是一个时间日期类型,在之后的代码中 $address->last_used_at
返回的就是一个时间日期对象(确切说是 Carbon
对象,Carbon
是 Laravel 默认使用的时间日期处理类)。public function user()
与 User
模型关联,关联关系是一对多(一个 User
可以有多个 UserAddress
,一个 UserAddress
只能属于一个 User
)。public function getFullAddressAttribute()
创建了一个访问器,在之后的代码里可以直接通过 $address->full_address
来获取完整的地址,而不用每次都去拼接。接下来在 User
模型中关联上 UserAddress
模型:
app/Models/User.php
.
.
.
public function addresses()
{
return $this->hasMany(UserAddress::class);
}
.
.
.
然后执行迁移:
$ php artisan migrate
通过 make:controller
命令创建 UserAddressesController
控制器:
$ php artisan make:controller UserAddressesController
添加 index()
方法:
app/Http/Controllers/UserAddressesController.php
.
.
.
public function index(Request $request)
{
return view('user_addresses.index', [
'addresses' => $request->user()->addresses,
]);
}
.
.
.
我们把当前用户下的所有地址作为变量 $addresses
注入到模板 user_addresses.index
中并渲染。
接下来我们要创建收货地址列表页面的模板:
$ mkdir -p resources/views/user_addresses
$ touch resources/views/user_addresses/index.blade.php
resources/views/user_addresses/index.blade.php
@extends('layouts.app')
@section('title', '收货地址列表')
@section('content')
<div class="row">
<div class="col-lg-10 col-lg-offset-1">
<div class="panel panel-default">
<div class="panel-heading">收货地址列表</div>
<div class="panel-body">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>收货人</th>
<th>地址</th>
<th>邮编</th>
<th>电话</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach($addresses as $address)
<tr>
<td>{{ $address->contact_name }}</td>
<td>{{ $address->full_address }}</td>
<td>{{ $address->zip }}</td>
<td>{{ $address->contact_phone }}</td>
<td>
<button class="btn btn-primary">修改</button>
<button class="btn btn-danger">删除</button>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
@endsection
routes/web.php
.
.
.
Route::group(['middleware' => 'email_verified'], function() {
Route::get('user_addresses', 'UserAddressesController@index')->name('user_addresses.index');
});
.
.
.
把路由放在
email_verified
的路由组中
在浏览器中访问:http://shop.test/user_addresses
现在数据库里是空的,我们可以通过工厂文件来自动生成收货地址假数据。
之前通过 make:model
的 -f
参数让 Laravel 自动生成了工厂文件,但是由于我们加了前缀 Models
,所以生成的工厂文件名字是 ModelsUserAddressFactory
,我们需要把这个文件重命名一下:
$ mv database/factories/ModelsUserAddressFactory.php database/factories/UserAddressFactory.php
$ composer dumpautoload
重命名工厂文件之后需要执行
composer dumpautoload
,否则会找不到对应的工厂文件。
factory
工厂文件会使用 faker
来自动生成字段的内容,默认情况下是英文,我们可以修改成中文:
config/app.php
.
.
.
'faker_locale' => 'zh_CN', // 新增一个配置项
.
.
.
接下来编辑工厂文件:
database/factories/UserAddressFactory.php
use Faker\Generator as Faker;
$factory->define(App\Models\UserAddress::class, function (Faker $faker) {
$addresses = [
["北京市", "市辖区", "东城区"],
["河北省", "石家庄市", "长安区"],
["江苏省", "南京市", "浦口区"],
["江苏省", "苏州市", "相城区"],
["广东省", "深圳市", "福田区"],
];
$address = $faker->randomElement($addresses);
return [
'province' => $address[0],
'city' => $address[1],
'district' => $address[2],
'address' => sprintf('第%d街道第%d号', $faker->randomNumber(2), $faker->randomNumber(3)),
'zip' => $faker->postcode,
'contact_name' => $faker->name,
'contact_phone' => $faker->phoneNumber,
];
});
我们预先设置了一批省市区,通过 randomElement()
方法随机取出一个。
下面我们在 tinker 里测试一下刚创建的工厂文件:
$ php artisan tinker
>>> factory(App\Models\UserAddress::class, 3)->create(['user_id' => 1])
create()
方法来存入数据库:
factory(App\Models\UserAddress::class, 3)
代表创建 3 个 UserAddress
对象。
create()
方法可以接受一个数组参数,数组中的数据会作为字段的值保存到数据库中,这里我们将刚刚创建的 3 个地址的 user_id
字段设为了 1
,也就是把这 3 个地址与 id
为 1
的用户关联了起来,也就是我们注册的第一个用户。
现在我们再访问 http://shop.test/user_addresses ,即可看到数据
地址列表页面就做好了,现在我们在菜单栏添加一下入口:
_resources/views/layouts/header.blade.php
.
.
.
<ul class="dropdown-menu" role="menu">
<li>
<a href="{{ route('user_addresses.index') }}">收货地址</a>
</li>
.
.
.
</ul>
.
.
.
刷新页面,点击右上角的头像可查看效果