代码之家  ›  专栏  ›  技术社区  ›  Ben

Laravel查询范围具有动态值

  •  0
  • Ben  · 技术社区  · 7 年前

    我正在努力找到能够满足我需求的生成器与原始SQL的正确组合。 我有一个允许用户配置的设置 X 数量 TournamentQuizmasters 需要用于 十、 数量 Teams .为了提高效率,我需要在MySQL级别上进行此计算 ,因此我可以快速查询所有符合条件的团队。我有其他查询范围来确定合格团队是什么(例如。 withEnoughPlayers() )。

    这个代码不起作用,但我认为它传达了我的意图。

    // A collection of Teams
    class TeamSet extends Model {
        public function scopeWithEnoughQuizmastersBasedOnTeamCount(Builder $q, Tournament $tournament)
        {
            // Pull only the groups that bring enough quizmasters.  The required number
            // of quizmasters is based off of the number of teams they're bringing.
            return $q->whereHas('group', function (Builder $q) use ($tournament) {
                    $q->has(
                        'tournamentQuizmasters',
                        '>=',
                        DB::raw('FLOOR(('.$tournament->settings->quizmastersToRequireByTeamCount().' * '.$q->selectRaw('COUNT(*)')->teams()->withEnoughPlayers($tournament)->toSql().') / '.$tournament->settings->teamCountToRequireQuizmastersBy().')')
                    );
            });
        }
    }
    

    运行我得到的查询 Call to undefined method Illuminate\Database\Eloquent\Builder::teams() 我认为这是因为 selectRaw() 继续进行。我也不认为我真的可以打电话 ->teams() 我在这里的方式,但我有点盲目,我应该如何改变这一点,以获得我正在寻找的结果。

    如何在利用查询生成器的同时执行此动态表达式,以便利用我的作用域?

    我用的是Laravel 5.7

    型号(&M);关系

    class TeamSet {
        public function group() : BelongsTo
        {
            return $this->belongsTo(Group::class);
        }
        public function teams() : HasMany
        {
            return $this->hasMany(Team::class)
        }
    }
    
    class Team {
        public function teamSet() : BelongsTo
        {
            return $this->belongsTo(TeamSet::class)
        }
    }
    
    class Group {
    
        public function tournamentQuizmasters() : HasMany
        {
            return $this->hasMany(TournamentQuizmaster::class);
        }
    
        public function teams() : HasManyThrough
        {
            return $this->hasManyThrough(Team::class, TeamSet::class);
        }
    }
    
    class Tournament {
        public function teamSets() : HasMany
        {
            return $this->hasMany(TeamSet::class);
        }
    
        public function teams() : HasManyThrough
        {
            return $this->hasManyThrough(Team::class, TeamSet::class);
        }
    }
    
    class TournamentQuizmaster {
        public function group() : BelongsTo
        {
            return $this->belongsTo(Group::class);
        }
    
        public function tournament() : BelongsTo
        {
            return $this->belongsTo(Tournament::class);
        }
    }
    

    型号说明:

    • TeamSet -表示团队集合的单个实体。这使我们的用户能够在多场比赛中使用同一组球队。
    • Team -球员的集合
    • Group -组名称。这在应用程序中的其他位置使用,但每 团队集合 属于某个组。
    • Tournament -不言而喻
    • TournamentQuizmaster -比赛的裁判或裁判。根据团队数量,每组需要带X个

    $锦标赛->设置

    这作为json存储在数据库中,但转换为对象,因此我有一个合理的位置来保留默认值。下面是该类的一个片段:

    use Illuminate\Support\Fluent;
    
    class Settings extends Fluent
    {
        const DEFAULT_MAXIMUM_PLAYERS_PER_TEAM = 5;
        const DEFAULT_MINIMUM_PLAYERS_PER_TEAM = 3;
    
        public function __construct($attributes = [])
        {
            if ($attributes !== null) {
                parent::__construct($attributes);
            }
        }
    
        public function shouldRequireQuizmasters() : bool
        {
            return $this->get('requireQuizmasters', 'none') != 'none';
        }
    
        public function shouldRequireQuizmastersByGroup() : bool
        {
            return $this->get('requireQuizmasters', null) == 'group';
        }
    
        public function quizmastersToRequireByGroup() : int
        {
            return $this->get('quizmastersToRequireByGroup', 1);
        }
    
        public function setQuizmastersToRequireByGroup(int $quizmasterCount)
        {
            $this->quizmastersToRequireByGroup = $quizmasterCount;
        }
    
        public function shouldRequireQuizmastersByTeamCount() : bool
        {
            return $this->get('requireQuizmasters', null) == 'team_count';
        }
    
        public function quizmastersToRequireByTeamCount() : int
        {
            return $this->get('quizmastersToRequireByTeamCount', 1);
        }
    

    存储在数据库中的json最终看起来像:

    {"collectShirtSizes":"1","collectQuizmasterPreferences":"1","allowsGuestPlayers":true,"minimumPlayersPerTeam":3,"maximumPlayersPerTeam":6,"requireQuizmasters":"group","quizmastersToRequireByGroup":1,"quizmastersToRequireByTeamCount":1,"teamCountToRequireQuizmastersBy":2}
    
    0 回复  |  直到 7 年前
        1
  •  1
  •   Ben    7 年前

    在下面的文章中,我已经能够使用subSelect技术完成一些类似的事情。 https://reinink.ca/articles/dynamic-relationships-in-laravel-using-subqueries

    基于此,您可以在组查询中获得添加了足够球员的球队数量,并将其与锦标赛测验大师的数量进行比较。我希望我能充分理解你的提问。也许是这样吧。

    /// In Group
    public function scopeHasRequiredAmount(Builder $builder, Tournament $tournament)
    {
        return $builder->withCount('tournamentQuizmasters')
            ->teamsWithEnoughPlayersCount()
            ->havingRaw(
                'tournamentQuizmasters_count > FLOOR((' . $tournament->settings->quizmastersToRequireByTeamCount() .
                '* teams_with_enough_players_count ) /'
                . $tournament->settings->teamCountToRequireQuizmastersBy() . ')'
            );
    }
    
    /// adds count of teams with enough players to query
    public function scopeTeamsWithEnoughPlayersCount(Builder $builder, Tournament $tournament)
    {
        return $builder->addSubSelect('teams_with_enough_players_count', Team::selectRaw('count(*)')
            ->whereColumn('groups.id', 'teams.group_id')
            ->withEnoughPlayers($tournament)
        );
    }
    
    /// In Teamset
    function scopeWithEnoughQuizmastersBasedOnTeamCount(Builder $builder, $tournament)
    {
        return $builder->whereHas('group', function (Builder $q) use ($tournament) {
            $q->hasRequiredAmount($tournament);
        });
    
    }