【PHP】Laravel开发 —— 十、收货地址列表

收货地址

收货地址是电商网站必须功能,本次需要实现收货地址列表的展示。

1. 整理字段

首先,需要整理好 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

2. 创建模型

通过 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

3. 创建控制器

通过 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 中并渲染。

4. 创建模板

接下来我们要创建收货地址列表页面的模板:

$ 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

5. 创建路由

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

现在数据库里是空的,我们可以通过工厂文件来自动生成收货地址假数据。

6. 工厂文件

之前通过 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 个地址与 id1 的用户关联了起来,也就是我们注册的第一个用户。

现在我们再访问 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>
.
.
.

刷新页面,点击右上角的头像可查看效果

你可能感兴趣的:(PHP,Laravel)