在我的应用中,我有游戏和锦标赛,其中一个游戏可选地属于锦标赛。游戏和锦标赛都可以与PhotoAlbum拥有belongsTo关系。
我现在想要的是,如果游戏没有PhotoAlbum,它将尝试将其归还为Tournament的PhotoAlbum(如果存在这两种情况)。如果我使用withCount
进行查询,我也希望它采用这条路线。
我尝试将支票添加到游戏的专辑关系中,但这似乎不起作用:
class Game extends Model {
public function album()
{
if ($this->album_id == null && $this->tournament_id != null ) {
return $this->tournament->album();
}
return $this->belongsTo('App\Models\PhotoAlbum');
}
}
需要在查询生成器中与,而不必使我不得不编写一堆新的if / then检查整个现有代码。withCount()
一起使用
-
不必担心withCount
的工作,因为我可以创建一个适用于album_count
的自定义属性获取器。
答案 0 :(得分:0)
您可以在下面这样做
$game = Game::find(1);
if(! isset($game->album)) { // you can different if's here to check if not album exist
return $game->tournament->album;
}
答案 1 :(得分:0)
您是否尝试过HasOneThrough
关系?
public function tournamentAlbum(): HasOneThrough
{
return $this->hasOneThrough(Album::class, Tournament::class);
}
我想没有简单的方法来扩大当前关系并防止重构。这是因为使用空的模型实例可以部分解决急切的负载。
答案 2 :(得分:0)
我不想成为那个回答自己问题的人,但是我讨厌成为一个不愿意分享更多工作的人。
我最终创建了一个视图,该视图可以进行联接并在数据级别进行检查。这使它变得简单join
和ifnull
,然后将模型更改为使用该表而不是基础表。这对于读取和查询很有用,但显然对CRUD操作无效。
由于该视图是不可更新的,因此我在准备进行任何写操作时最终进入了模型事件系统,以将模型切换到基本表,然后在完成时将其切换回基本表。我采用观察者模式,因为它可以使所有内容保持干净。
观察者:
<?php
namespace App\Models\Observers;
use App\Models\Contracts\IPersistTo;
/**
* Class PersistToObserver
*
*
* @package App\Models\Observers
*/
class PersistToObserver
{
protected function useReadTable(IPersistTo $model)
{
$model->setTable($model->getReadTable());
}
protected function useWriteTable(IPersistTo $model)
{
$model->setTable($model->getWriteTable());
}
/**
* Switch the model to use the write table before it goes to the DB
* @param IPersistTo $model
*/
public function creating(IPersistTo $model)
{
$this->useWriteTable($model);
}
/**
* Switch the model to use the write table before it goes to the DB
* @param IPersistTo $model
*/
public function updating(IPersistTo $model)
{
$this->useWriteTable($model);
}
/**
* Switch the model to use the write table before it goes to the DB
* @param IPersistTo $model
*/
public function saving(IPersistTo $model)
{
$this->useWriteTable($model);
}
/**
* Switch the model to use the write table before it goes to the DB
* @param IPersistTo $model
*/
public function deleting(IPersistTo $model)
{
$this->useWriteTable($model);
}
/**
* Switch the model to use the write table before it goes to the DB
* @param IPersistTo $model
*/
public function restoring(IPersistTo $model)
{
$this->useWriteTable($model);
}
/**
* Model has been written to the BD, switch back to the read table
* @param IPersistTo $model
*/
public function created(IPersistTo $model)
{
$this->useReadTable($model);
}
/**
* Model has been written to the BD, switch back to the read table
* @param IPersistTo $model
*/
public function updated(IPersistTo $model)
{
$this->useReadTable($model);
}
/**
* Model has been written to the BD, switch back to the read table
* @param IPersistTo $model
*/
public function saved(IPersistTo $model)
{
$this->useReadTable($model);
}
/**
* Model has been written to the BD, switch back to the read table
* @param IPersistTo $model
*/
public function deleted(IPersistTo $model)
{
$this->useReadTable($model);
}
/**
* Model has been written to the BD, switch back to the read table
* @param IPersistTo $model
*/
public function restored(IPersistTo $model)
{
$this->useReadTable($model);
}
}
IPersistTo合同/接口
<?php
namespace App\Models\Contracts;
interface IPersistTo
{
/**
* @return string - the name of the table to read from (should be the same as the default $table)
*/
public function getReadTable();
/**
* @return string - the name of the table to write to
*/
public function getWriteTable();
/**
* Set the table associated with the model. Fulfilled by Model.
*
* @param string $table
* @return $this
*/
public function setTable($table);
}
我的模型中的设置(被截断为仅仅是相关信息)
class Game extends Model implements IPersistTo {
protected $table = 'game_with_album_fallback';
/**
* @return string - the name of the table to read from (should be the same as the default $table)
*/
public function getReadTable()
{
return 'game_with_album_fallback';
}
/**
* @return string - the name of the table to write to
*/
public function getWriteTable()
{
return 'games';
}
}
最后将所有这些连接在一起,将以下行添加到AppServiceProvider的启动方法中:
Game::Observe(PersistToObserver::class);