[英]Laravel one to many relationship with comma separated column value
在我的 Laravel 8 項目 (API) 中,我有一個名為StatusPage
的模型和一個名為Monitor
的模型。 用戶可以創建多個監視器並創建一個狀態頁面並選擇哪些監視器鏈接到他們的狀態頁面,這些監視器以逗號分隔列表的形式存儲在我的StatusPage
模型中的monitors
列中,例如:1,5,7, 8
在我的控制器的索引函數中,我想拉回一個狀態頁面列表,其中每個狀態頁面都包含一個監視器數組(如果有的話)基於我的monitors
列中的值,目前,我的函數如下所示:
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
try {
$pages = StatusPage::where('user_id', Auth::id())->get();
// not found
if (!$pages) {
return response()->json([
'success' => false,
'message' => 'We can\'t find any status pages'
], 404);
}
return response()->json([
'success' => true,
'message' => 'Your status pages',
'pages' => $pages ?? []
], 200);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => $e
], 422);
}
}
我的StatusPage
模型如下所示:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;
class StatusPage extends Model
{
use HasFactory, SoftDeletes;
/**
* Indicates if the model's ID is auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'status_pages';
}
我將如何在這種情況下使用一對多,因為這種關系希望從列中提取值,而我將監視器存儲在單個列中?
我怎樣才能做到這一點?
從您現有的架構設計來看,我認為您不能使用一對多。
您可以嘗試 2 個選項。
您需要更改架構。 在 Monitor 上,您可以添加一個列 status_page_id 這是一個外鍵,並在模型 StatusPage 上添加到模型 Monitor 的一對多關系。 這是最佳做法。
您可以在 StatusPage 上創建一個訪問器(getter)。
// #1
public function monitors()
{
return $this->hasMany(Monitor::class);
}
// #2
public function getMonitorsAttributes()
{
$monitorId = $this->getOriginal('monitors');
return Monitor::whereIn('id', explode(',', $monitorId))->get();
}
訪問器和修改器文檔在這里: https : //laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators
不幸的是,您的關系不是 Laravel 處理的標准一對多關系。
以前的答案會起作用。 但是,它可能不是最高效的方法。 因為它對每個狀態頁面執行查詢。
我得到了一個可以更快一點的解決方案,類似於在幕后進行急切加載的工作方式。
首先,為了更輕松地使用此monitors
列。 讓我們為它創建一個自定義演員表。
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class ArrayToString implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
return explode(',', $value);
}
public function set($model, $key, $value, $attributes)
{
return implode(',', $value);
}
}
use App\Casts\ArrayToString;
class StatusPage extends Model
{
protected $casts = [
'Monitors' => ArrayToString::class,
];
}
然后,在您的控制器中:
public function index()
{
$pages = StatusPage::where('user_id', Auth::id())->get();
// Get all relevant monitors at once.
$monitors = $pages->map->monitors
->collapse()
->unique()
->pipe(function ($monitorIds) {
return Monitor::findMany($monitorIds->toArray());
})
// Assign related monitors to each status page.
$pages->each(function ($page) use ($monitors) {
$relevantMonitors = $monitors->filter(function ($monitor) use
($page) {
return in_array($monitor->id, $page->monitor);
});
$page->monitors = $relevantMonitors;
})
return $pages;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.