【问题标题】:Laravel: Tree filter children recursiveLaravel:树过滤子递归
【发布时间】:2020-03-12 11:53:01
【问题描述】:

我似乎无法对以树模型格式定义的所有子节点应用过滤带有急切加载机制

这是我的模型定义(效果很好):

class Section extends Model
{
    [...]
    /**
     * @return HasOne
     */
    public function parent()
    {
        return $this->hasOne(
            self::class,
            'Id',
            'IdParent'
        )->with('parent');
    }

    /**
     * @return HasMany
     */
    public function children()
    {
        return $this->hasMany(
            self::class,
            'IdParent',
            'Id'
        )->with('children');
    }
    [...]
}

现在我想根据“条件对象”过滤掉递归

public function getMachines(SectionCriteria $sectionCriteria = NULL)
{
    /**
     * @var $builder Builder|Section
     */
    $builder = Section::with([
        'children' => function ($query) use ($sectionCriteria) {
            if ($sectionCriteria) {
                foreach ($sectionCriteria->getFilterFlags() as $flagName => $flagValue) {
                    if ($flagValue) {
                        $query->whereFlag($flagName);  //Custom implementation
                    } else {
                        $query->whereNotFlag($flagName); //Custom implementation
                    }
                }
            }
        }
    ]);

这适用于树的第一级。

我的问题是:有没有办法将对象传递给children() 关系,以便我可以递归应用过滤器(适用于所有级别)?

比如说:

P.S:这是不可能的,因为只接受一个回调作为参数

public function children($parameters)
{
    return $this->hasMany(
        self::class,
        'IdParent',
        'Id'
    )->with('children'=>$parameters);
}

我不想使用的东西(关于 SOLID 原则):

  1. 创建一个包含标准的静态类变量
  2. 任何类型的全局变量

【问题讨论】:

    标签: php laravel eloquent


    【解决方案1】:

    我还尝试检索子递归(并应用过滤器),但最终得到更多查询,因此 Eloquent 优化得非常好...

    我使用了技巧 #1(创建一个静态类变量),虽然我不太喜欢它,但它确实有效。

    型号

    /**
     * @var null|SectionCriteria
     */
    public static $childrenFilter = NULL;  //This can be whatever you need since it's static
    
    
    /**
     * @return HasMany
     */
    public function children()
    {
        return $this->hasMany(
            self::class,
            'IdParent',
            'Id'
        )->with(['children'=>self::searchChild()]);
    }
    
    /**
     * @return \Closure
     */
    public function searchChild()
    {
        return function ($builder) {
            if (Section::$childrenFilter) {
               foreach ($sectionCriteria->getFilterFlags() as $flagName => $flagValue) {
                    if ($flagValue) {
                        $query->whereFlag($flagName);  //Custom implementation
                    } else {
                        $query->whereNotFlag($flagName); //Custom implementation
                    }
                }
            }
        };
    }
    
    /**
     * @param SectionCriteria $criteria
     */
    public static function setChildSearch(SectionCriteria $criteria)
    {
        Section::$childrenFilter = $criteria;
    }
    
    /**
     * Remove the search criteria filter
     */
    public static function clearChildSearch()
    {
        Section::$childrenFilter = NULL;
    }
    

    Repository(实际使用)

    /**
     * @param SectionCriteria|NULL $sectionCriteria
     * @return Section[]|Collection
     */
    public function getMachines(SectionCriteria $sectionCriteria = NULL)
    {
        /**
         * @var $builder Builder|Section
         */
        $builder = Section::with(['children']); //Here I do not need the root elements to be filtered, If needed then use: Section::with(['children'=>Section::searchChild()])
        Section::setChildSearch($sectionCriteria);
        $builder->orderBy('Name');
        $results = $builder->get();
        Section::clearChildSearch();
        return $results;
    }
    

    再次......不是很漂亮,但它可以完成工作

    :另一种方法(将对此进行测试)是扩展 Builder

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-06
      • 1970-01-01
      • 2011-02-18
      • 1970-01-01
      相关资源
      最近更新 更多