本文目录
前言
在构建电商平台或任何需要处理地理位置信息的应用时,准确且高效地管理省市区数据及用户地址信息显得尤为重要。Laravel以其强大的数据库ORM、灵活的路由系统和资源控制器,为开发者提供了构建这类功能的强大支持。
本指南将引导您完成从基础数据构建到复杂功能实现的全过程。首先,我们将学习如何添加省市县数据,创建地址模型以规范数据存储,并通过控制器和路由的设计实现地址信息的基本操作。接下来,我们将深入探讨地址管理的进阶功能,包括地址验证、资源API控制器的配置、以及订单地址的修改等。每一步都将配以详细的实现步骤和测试验证,确保您能够掌握这些关键技能。
通过本指南的学习与实践,您将能够构建一个高效、可维护的地址管理系统,为您的应用提供更加丰富的地理信息服务,增强用户体验并提升应用的价值。
1、省市区
为什么我们这里省市区要写在后台,为什么不直接让前端用前端组件,因为这边的话,我们最后走后台,数据可控制,如果前端一套web
组件,一套小程序组件,或者一套app
的组件,那么数据格式不一样,就会有各种问题,所以这个数据最好我们给前端。
1.1 添加省市县数据
在database
文件夹下新建sql
文件夹,将省市县数据文件放入:
运行命令php artisan make:seeder CitySeeder
在CitySeeder.php
中写入:
// 创建省市区表,并填充数据
DB::unprepared(file_get_contents(__DIR__.'/../sql/provinice_city_county_town.sql'));
运行填充命令:php artisan db:seed --class=CitySeeder
由于城市的数据比较多,所以在一开始填充之后写入辅助函数建立缓存:
/**
* 城市相关的缓存信息
*/
if (!function_exists('city_cache')) {
function city_cache($pid = 0) {
// cache()->forget('city_children'.$pid);
return cache() ->rememberForever('city_children'.$pid, function () use($pid) {
return City::where('pid', $pid)->get()->keyBy('id');
});
}
}
1.2 创建地址模型
创建city
模型:php artisan make:model City
:
设置属性让它去找city
表,因为不找的话,它默认去找复数形式的:
protected $table = 'city';
1.3 创建地址控制器
运行命令php artisan make:controller CityController
在城市模型中加入关联的子类:
/**
* 子类
*/
public function children() {
return $this->hasMany(City::class, 'pid', 'id');
}
控制器中写入:
/**
* 省市县数据
*/
public function index(Request $request) {
$resData = city_cache($request->query('pid', 0));
return $resData;
}
1.4 创建地址路由
/**
* 地址
*/
$api->get('city', [CityController::class, 'index']);
1.5 测试效果
不传pid
时获取到所有的省:
前端用户选中其中一个省,把id
传进去获得市的数据:
将点击市,获取市下的数据:
2、地址管理
2.1 创建地址模型以及迁移文件
运行命令php artisan make:model Address -m
在迁移文件中创建表结构:
Schema::create('addresses', function (Blueprint $table) {
$table->id();
$table->integer('user_id')->comment('用户id');
$table->string('name')->comment('收获人');
$table->integer('city_id')->comment('city表中的id');
$table->string('address')->comment('详细地址');
$table->string('phone')->comment('手机号');
$table->tinyInteger('is_default')->default(0)->comment('默认地址 0=>不是默认,1=>是默认');
$table->timestamps();
$table->index('user_id'); // 查询索引
});
运行命令php artisan migrate
:
2.2 创建地址验证类
运行命令php artisan make:request Web/AddressRequest
:
写入:
public function rules()
{
return [
'name' => 'required',
'city_id' => [
'required',
function ($attribute, $value, $fail) {
$city = City::find($value);
if (empty($city)) $fail('城市不存在');
},
],
'address' => 'required',
'phone' => 'required|regex:/^1[3-9]\d{9}$/',
];
}
/**
* 提示消息
*/
public function messages() {
return [
'name.required' => '收货人必填',
'city_id.required' => '地址不能为空',
'address.required' => '详细地址不能为空',
'phone.required' => '手机号不能为空',
];
}
2.3 配置地址transform创建地址资源API控制器
给模型配置可批量插入的字段:
use HasFactory;
protected $fillable = ['user_id','name', 'phone', 'address', 'city_id', 'is_default'];
在City.php
模型中写入查找父级的联动:
/**
* 查找父类
*/
public function parent() {
return $this->belongsTo(City::class, 'pid', 'id');
}
在辅助函数中写入根据区id
查找上级联动数据:
/**
* 通过区ID 查询完整省市区数据
*/
if (!function_exists('city_name')) {
function city_name($city_id) {
$city = City::where('id', $city_id)->with('parent.parent.parent')->first();
// $str = $city['parent']['parent']['parent']['name'] ?? '';
// $str .= $city['parent']['parent']['name'] ?? '';
// $str .= $city['parent']['name'] ?? '';
// $str .= $city['name'] ?? '';
$str = [
$city['parent']['parent']['parent']['name'] ?? '',
$city['parent']['parent']['name'] ?? '',
$city['parent']['name'] ?? '',
$city['name'] ?? ''
];
return trim(implode(' ', $str));
}
}
创建AddressTransformer.php
写入:
<?php
namespace App\Transformers;
use App\Models\Address;
use League\Fractal\TransformerAbstract;
class AddressTransformer extends TransformerAbstract {
public function transform(Address $address) {
return [
'id' => $address->id,
'name' => $address->name,
'city_id' => $address->city_id,
'city_name' => city_name($address->city_id),
'phone' => $address->phone,
'address' => $address->address,
'is_default' => $address->is_default,
'created_at' => $address->created_at,
'updated_at' => $address->updated_at,
];
}
}
运行命令php artisan make:controller Web/AddressController --api
写入增删改查以及是否默认方法:
<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\BaseController;
use App\Http\Requests\Web\AddressRequest;
use App\Models\Address;
use App\Transformers\AddressTransformer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class AddressController extends BaseController
{
/**
* 我的地址列表
*/
public function index()
{
$address = Address::where('user_id', auth('api')->id())->get();
return $this->response->collection($address, new AddressTransformer());
}
/**
* 添加地址
*/
public function store(AddressRequest $request)
{
Address::create([
'user_id' => auth('api')->id(),
'name' => $request->input('name'),
'phone' => $request->input('phone'),
'address' => $request->input('address'),
'city_id' => $request->input('city_id'),
]);
return $this->response->created();
}
/**
* 地址详情
*/
public function show(Address $address)
{
return $this->response->item($address, new AddressTransformer());
}
/**
* 更新地址
*/
public function update(AddressRequest $request, Address $address)
{
$address->update([
'user_id' => auth('api')->id(),
'name' => $request->input('name'),
'phone' => $request->input('phone'),
'address' => $request->input('address'),
'city_id' => $request->input('city_id'),
'is_default' => $request->input('is_default')
]);
return $this->response->noContent();
}
/**
* 删除地址
*/
public function destroy(Address $address)
{
$address->delete();
return $this->response->noContent();
}
/**
* 默认地址
*/
public function isDefault(Address $address)
{
if ($address->is_default == 1) {
return $this->response->noContent(); // 如果改地址已经设置默认地址 直接返回
}
try {
DB::beginTransaction(); // 开启事物, 防止一个设置成功一个设置失败
// 先把所有的地址都设置为非默认
$default_address = Address::where('user_id', auth('api')->id())
->where('is_default', 1)
->first();
if (!empty($default_address)) {
$default_address->is_default = 0;
$default_address->save();
}
// 在把当前的设置成默认
$address->is_default = 1;
$address->save();
DB::commit();
return $this->response->noContent();
} catch (\Exception $e) {
DB::rollback();
throw $e;
}
}
}
2.4 配置地址路由
// 地址增删改查
$api->resource('address', AddressController::class);
// 设置默认地址
$api->patch('address/{address}/default', [AddressController::class, 'isDefault']);
2.5 订单地址修改
由于之前没有写地址相关的api,地址那块是模拟的假数据,现在把它修改过来:
// 地址数据
$address = Address::where('user_id', auth('api')->id())
->orderBy('is_default', 'desc')
->get();
还有一处地方就是在提交订单时候验证地址是否存在:
'address_id' => 'required|exixts:addresses,id'
2.6 测试效果
1、添加地址
2、地址列表
3、修改地址
4、地址详情
5、删除地址
6、设置默认地址
在学习的php的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。