解决访问器与数据填充冲突问题
所用的知识点
1.迁移文件的建立
2.数据填充
3.经过观察者监听模型事件
4.注册观察者
5.模型php
素材须要
数据库
字段 | value |
---|---|
id | 分类id |
name | 分类名 |
parent_id | 父级id |
image | 分类图标 |
level | 当前分类的等级 |
sort | 排序 |
possess | 该分类的全部父类 |
GoodsCategory模型
在category定义一个与上级以及子级的模型关联。而后添加三个获取器;1.获取全部的上级id,2.根据获取的id获取子级的全部上级,而且根据level排序。 至于以后一个只是获取全部的上级名称数据库
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; /** * 商品分类 */ class GoodsCategory extends Model { protected $fillable = ['name', 'category_image']; public function parent() { //反向关联 return $this->belongsTo(GoodsCategory::class); } public function children() { //一对多 return $this->hasMany(GoodsCategory::class, 'parent_id'); } //定义一个访问器,获取全部祖先类目的ID值 public function getPossessIdsAttribute() { //array_filter 将数组中的空值移除 return array_filter(explode('-', trim($this->possess, '-'))); } //定义一个访问器,获取祖先类目并按层级排序 public function getAncestorsAttribute() { return GoodsCategory::query() ->whereIn('id', $this->possess_ids) //按层级排序 ->orderBy('level')->get(); } //定义一个访问器,获取以 - 为分隔的全部祖先类目的名称以及当前类目的名称 public function getFullNameAttribute() { return $this->ancestors //获取全部祖先类 ->pluck('name') //获取祖先类目的name 字段为一个数组 ->push($this->name)//获取当前类目的 name 字段加到数组的末尾 ->implode(' - '); //用 - 符合将数组的值组成一个字符串 } public function getLevelAttribute($value) { $data = [ '0' => '根目录', '1' => '二级', '2' => '三级', ]; return (is_null($value)) ? $data : $data[$value]; } /** * 测试方法 * @return [type] [description] */ public function test() { $category = GoodsCategory::where('id', 10)->first(); $data = $category->ancestors->toArray(); return $data; } }
建立GoodsCategoryTableSeeder.php数据填充文件
命令:php artisan make:seeder GoodsCategoryTableSeeder
数组
<?php use App\Models\GoodsCategory; use Illuminate\Database\Seeder; class GoodsCategoryTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { $categories = [ [ 'name' => '手机配件', 'sort' => '0', 'children' => [ [ 'name' => '手机壳', 'sort' => '0', 'children' => [ [ 'name' => '华为V10手机', 'sort' => '0', ], [ 'name' => '小米', 'sort' => '1', ], ], ], [ 'name' => '数据线', 'sort' => '4', 'children' => [ [ 'name' => '苹果数据线', 'sort' => '0', ], [ 'name' => '安卓数据线', 'sort' => '1', ], ], ], [ 'name' => '耳机', 'sort' => '0', 'children' => [ [ 'name' => '有线耳机', 'sort' => '1', ], [ 'name' => '蓝牙耳机', 'sort' => '0', ], ], ], ], ], [ 'name' => '六星果园', 'sort' => '0', 'children' => [ [ 'name' => '国产水果', 'sort' => '0', 'children' => [ [ 'name' => '苹果', 'sort' => '0', ], [ 'name' => '梨', 'sort' => '1', ], ], ], ] ] ]; foreach ($categories as $data) { $this->createCategory($data); } } public function createCategory($data, $parent = null) { // 建立一个分类 $category = new GoodsCategory([ 'name' => $data['name'], 'sort' => $data['sort'], ]); // 若是有父级参数,表明有父类目 if (!is_null($parent)) { // 将模型实例与给定的父实例关联。 $category->parent()->associate($parent); } // 保存到数据库 $category->save(); // 若是有children字段而且 children字段是一个数组 if (isset($data['children']) && is_array($data['children'])) { foreach ($data['children'] as $child) { $this->createCategory($child, $category); } } } }
建立GoodsCategoryObserver.php观察者
命令:php artisan make:observer GoodsCategoryObserver --model=GoodsCategory
app
<?php namespace App\Observers; use Log; use App\Models\GoodsCategory; class GoodsCategoryObserver { public function creating(GoodsCategory $goodsCategory) { //若是建立的是一个根类目 if (is_null($goodsCategory->parent_id)) { //讲层级设置为0 $goodsCategory->level = 0; //将path 设为 - $goodsCategory->possess = '-'; }else { //将层级设为父类目层级 + 1 $goodsCategory->level = $goodsCategory->parent->level +1; // 将path 设为父级目的的PATH 追加父级的id 并最后 跟上一个 - 分隔符 $goodsCategory->possess = $goodsCategory->parent->possess.$goodsCategory->parent_id.'-'; } } /** * Handle the goods category "created" event. * * @param \App\GoodsCategory $goodsCategory * @return void */ public function created(GoodsCategory $goodsCategory) { } /** * Handle the goods category "updated" event. * * @param \App\GoodsCategory $goodsCategory * @return void */ public function updated(GoodsCategory $goodsCategory) { // } /** * Handle the goods category "deleted" event. * * @param \App\GoodsCategory $goodsCategory * @return void */ public function deleted(GoodsCategory $goodsCategory) { // } /** * Handle the goods category "restored" event. * * @param \App\GoodsCategory $goodsCategory * @return void */ public function restored(GoodsCategory $goodsCategory) { // } /** * Handle the goods category "force deleted" event. * * @param \App\GoodsCategory $goodsCategory * @return void */ public function forceDeleted(GoodsCategory $goodsCategory) { // } }
建立数据库迁移文件
php artisan make:mmigration create_goods_category_table --create=goods_category
ide
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateGoodsCategoriesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('goods_categories', function (Blueprint $table) { $table->increments('id')->comment('商品类别主键id'); $table->string('name')->comment('类别名称'); $table->integer('parent_id')->default(0)->comment('父级类别id'); $table->string('image')->nullable()->comment('分类图片'); $table->integer('level')->default(0)->comment('分类等级'); $table->integer('sort')->default(0)->comment('分类排序'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('goods_categories'); } }
注册观察者
命令:php artisan make:provider ModelObserverServiceProvider
测试
<?php namespace App\Providers; use App\Observers\GoodsCategoryObserver; use App\Models\GoodsCategory; use Illuminate\Support\ServiceProvider; class ModelObserverProvider extends ServiceProvider { /** * Register services. * * @return void */ public function register() { // } /** * Bootstrap services. * * @return void */ public function boot() { GoodsCategory::observe(GoodsCategoryObserver::class); } }
而后在app里边注册进去便可
this
重现数据填充与访问器冲突
执行数据填充命令
php artisan db:seed --class=GoodsCategoryTableSeeder
而后打开数据库
url
日志检测问题
咱们会发现咱们自定义的数据都没有进去,只进去了第一行,这是为何呢!
咱们能够看到有个一报错信息是 A non-numeric value encountered,而且报到了观察者的19行,咱们在这里写个日志看看缘由
在把数据填充的命令执行一次
php artisan db:seed --class =GoodsCategoryOberserver
一样也给出了这里的报错信息,那么我们看看这level字段到底怎么回事
spa
检测level字段的问题
能够看到在模型里边定义了一个访问器来从新定义了level字段,那么问题就在这里了,这个时候咱们在注释了之后去执行填充命令
执行
查看数据库
这个时候就是能够的了
.net
解决访问器与数据填充时的冲突
虽然咱们在上边解决了这个问题,可是咱们定义的这个访问器是在后台显示数据的时候使用的。其实数据填充出现的问题,也就是咱们在后台进行数据添加时会报出的问题,因此这个问题不是一个注释解决的
1.在模型里边定义一个虚拟字段
2.修改以前的访问器
3.而后在执行填充命令
4.查看数据库
5.打开后台查看数据
解决设置的访问器不能正常使用
咱们在添加了虚拟属性后, 咱们的数据填充是好了,可是咱们在后台获取数据时并无做用
这个时候还须要一步操做,那就是把字段也给换成自定义的字段
这个时候在来查看,就没有问题了