mardi 2 avril 2019

Laravel - Implement Model Factory design pattern

I am trying to implement the Factory Design pattern with a Laravel Model. I have a Reward Model wich can have (for now) two types, the Points reward or the cashback reward.

I have the class Reward with everything

class Reward extends Model
{
    // class Reward stuff
}

And I also made two classes extending Reward (bboth of them with a globalScope refering to its type), PointsReward:

class PointsReward extends Reward
{
    protected $table = "rewards";

    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(
            'points', 
            function (Builder $builder) {
                $builder->whereHas(
                    'rewardType', 
                    function ($subQuery) {
                        $subQuery->where('type', 'Points');
                    }
                );
            }
        );
    }
}

and CashbackReward:

class CashbackReward extends Reward
{
    protected $table = "rewards";

    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(
            'cashback', 
            function (Builder $builder) {
                $builder->whereHas(
                    'rewardType', 
                    function ($subQuery) {
                        $subQuery->where('type', 'Points');
                    }
                );
            }
        );
    }
}

Now I was trying to made a Factory class:

class RewardFactory
{
    const CASHBACK_REWARD = 0;
    const POINTS_REWARD = 1;

    static function create(int $rewardType, array $data)
    {
        switch($rewardType){
        case self::CASHBACK_REWARD:
            return CashbackReward::create($data);
            break;
        case self::POINTS_REWARD:
            return PointsReward::create($data);
            break;
        default:
            throw new Exception("Not supported");
        }
    }

    static function find(int $id) : Reward
    {
        $main = Reward::find($id);

        switch($main->rewardType->type){
        case 'Points':
            return PointsReward::find($id);
            break;
        case 'Cashback':
            return CashbackReward::find($id);
            break;
        default:
            throw new Exception("Not supported");
            return null;
        }
    }
}

My problem is on the find method. Its purpose is to find a Reward by id (like Laravel method) and return an object depending on its rewardType->type property.

For sure this works, but I have to do 2 db queries to instantiate the object. Is there a better approach for this? If no, Is there a way to do this with only one query?



from Newest questions tagged laravel-5 - Stack Overflow https://ift.tt/2OFIhg7
via IFTTT

Aucun commentaire:

Enregistrer un commentaire