如果不存在关系,则使用父母的关系

时间:2019-09-17 04:44:14

标签: laravel eloquent

在我的应用中,我有游戏和锦标赛,其中一个游戏可选地属于锦标赛。游戏和锦标赛都可以与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');
    }
}

需要在查询生成器中与withCount()一起使用,而不必使我不得不编写一堆新的if / then检查整个现有代码。

-

不必担心withCount的工作,因为我可以创建一个适用于album_count的自定义属性获取器。

3 个答案:

答案 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)

我不想成为那个回答自己问题的人,但是我讨厌成为一个不愿意分享更多工作的人。

我最终创建了一个视图,该视图可以进行联接并在数据级别进行检查。这使它变得简单joinifnull,然后将模型更改为使用该表而不是基础表。这对于读取和查询很有用,但显然对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);