【问题标题】:Laravel model relationship across packagesLaravel 跨包的模型关系
【发布时间】:2018-10-09 03:19:33
【问题描述】:

我正在尝试重构我的项目,将 App 文件夹下的所有代码都放入单独的作曲家包中。但是我遇到了一个阻止程序,我可以使用一些输入来解决:

为了简化,我想创建 2 个包,CoreCustomers。我希望 Core 完全分离,不引用我的任何其他包。在Core 里面有一个模型叫做Business,在Customer 里面有一个模型叫做Customer。模型之间存在多对一的关系。当我想创建 Eloquent 关系方法时,问题就出现了。 Customer 依赖于 Core,所以这不是问题,$this->belongsTo(Business::class)。但是,要获得逆 Core 需要了解 Customer 模型,$this->hasMany(Customer::class)

有没有办法解决这个问题?就像从我的Customer 包中注册Business 模型上的方法一样?还是我把一切都搞反了?

编辑

对于不熟悉 Laravel 的人,关系被定义为模型类中的函数

class Business extends Model {
   public function customers() {
       return $this->hasMany(Customer::class);
   }
}

【问题讨论】:

  • 我不使用 laravel,但从 PHP 的角度来看,$this->hasMany(Customer::class)$this->hasMany($someclass) 相同,其中$someclass = Customer::class。因此,您可以在构造 Core 时将类名作为变量提供,从而通过注入它来打破依赖关系(如果这有意义的话)假设这都是运行时配置的东西。
  • 是的,这是解决问题的一种方法。但是我在我的问题中忽略了周围的功能(这很愚蠢......)。 $this->hasMany(Customer::class) 将被放置在一个名为 customers() 的函数中。这意味着我必须创建一个暗示存在关系的函数。我可以为每个“外部”关系创建一个魔术函数。但我不是那些的忠实粉丝......

标签: php laravel composer-php


【解决方案1】:

大多数人如何做到这一点是依赖注入,但这更多的是服务类型的事情,而不是模型关系类型的事情。正如你现在所拥有的那样,我可以想到几个选项。

  1. 将商务舱移出核心或将客户移入核心。这取决于这些模型对您的应用程序的“核心”程度。
  2. 依赖项使用枚举或注册表注入您的关系

       class Business extends Model {
           public function customers() {
               return $this->hasMany(ModelEnum::byName('Customers')->class());
           }
       }
    

 class Business extends Model {
       public function customers() {
           $models = collect(get_declared_classes())->filter(function ($item) {
               $item == 'YOURPACKAGENAME\Models\\Customers' ? $item : throw new Exception();

               return $item
           });

           return $this->hasMany($item);
       }
    }

我认为最好的办法是添加或删除类,拥有包内模型有点违背了将代码与包分开的目的。

【讨论】:

  • 我想完全避免添加函数customers。我想要的是 Core 包不知道与 Customer 相关的任何东西的存在
  • 那么听起来您最好的选择是将业务排除在核心之外。除非你乐于使用php runkit 做一些更骇人听闻的事情
  • 它是否在Core 或其他包中并不重要。如果我将Business 放在Business 包中,我仍然会得到循环依赖,但现在在BusinessCustomer 包之间。
  • 所以看起来你想要一个非依赖依赖,这是不可能的。就像我在评论中所说的那样,您可以使用您的其他包在运行时使用 php runkit 进行猴子补丁,但是如果没有在某处定义它,您将永远无法获得连接的功能。
【解决方案2】:

两种可能的解决方案:

  1. 直接声明关系,如果类不存在则抛出异常:

    public function customers() {
        if (class_exists(Customer::class)) {
            throw new \SomeException();
        }
    
        return $this->hasMany(Customer::class);
    }
    

    ::class 不会触发自动加载,因此即使类不可用也可以使用它。这仍然会创建对Customers 的依赖,但至少它是可选的。

  2. Customers 包可以为Business 提供适当的关系。所以如果你想使用Business类和Customers,你应该使用Customers\Models\Business而不是Core\Models\Business

    class Business extends \Core\Models\Business {
    
        public function customers() {
            return $this->hasMany(Customer::class);
        }
    }
    

    这将使Core 免受Customers 的依赖,但它根本无法扩展(你不能有第二个包,它会与Business 类做同样的事情)。

【讨论】:

    猜你喜欢
    • 2022-01-27
    • 2019-04-04
    • 2020-04-02
    • 2016-06-12
    • 2016-08-08
    • 1970-01-01
    • 2018-07-11
    相关资源
    最近更新 更多