解決訪問器與數據填充衝突問題
所用的知識點
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.打開後臺查看數據
解決設置的訪問器不能正常使用
咱們在添加了虛擬屬性後, 咱們的數據填充是好了,可是咱們在後臺獲取數據時並無做用
這個時候還須要一步操做,那就是把字段也給換成自定義的字段
這個時候在來查看,就沒有問題了