doubi2145 2018-04-30 19:41
浏览 67

Laravel Eloquent Polymorphic模型

I had a situation come up where I needed an Eloquent model to hydrate dynamically into a specific class that extends my "normal" eloquent model. Here's a generic layout loosely based on typical electronics:

Data Object:

['id', 'model_type', 'name', 'serial',...]
  • Model
    • Model Type A
    • Model Type B

If the data is all in a single table (MySQL), Laravel doesn't really have a way to pull that data directly as a polymorph. You can polymorph a relationship, but not a model directly.

Essentially the reasoning for this is to separate logic that may be concerned with one type, but not another. For example, Model Type A and Model Type B can both implement an interface which describes their capabilities, but the specific logic for A doesn't need to pollute B.

  • 写回答

1条回答 默认 最新

  • douke3007 2018-04-30 19:41
    关注

    My solution for this is to override the newFromBuilder method on the model (Laravel 5.6). Like so:

    App\Schemes\BaseScheme

    abstract class BaseScheme extends Electronic
    {
        // abstract methods to implement
        // ...
    }
    

    App\Schemes\ElectronicTypeA

    class ElectronicTypeA extends BaseScheme
    {
        // Electronic Type A logic
    }
    

    App\Schemes\ElectronicTypeB

    class ElectronicTypeB extends BaseScheme
    {
        // Electronic Type B logic
    } 
    

    App\Models\Electronic

    use Illuminate\Database\Eloquent\Model;
    
    class Electornic extends Model
    {
        public function newFromBuilder($attributes = [], $connection = null)
        {
            if (!class_exists($attributes->model_type)) {
                throw new \Exception("Invalid Scheme ({$attributes->model_type})"); 
            }
    
            $class = $attributes->model_type;
            $model = new $class;
    
            if (!$model instanceof \App\Schemes\BaseScheme) {
                throw new \Exception("Scheme class is invalid ({$attributes->model_type})");
            }
    
            $model->exists = true;
    
            $model->setRawAttributes((array) $attributes, true);
    
            $model->setConnection($connection ?: $this->getConnectionName());
    
            $model->fireModelEvent('retrieved', false);
    
            return $model;
        }
    

    Where \App\Schemes\BaseScheme is the abstract all the logic models extend. \App\Schemes\BaseScheme also extends the original Eloquent model.

    The really nice thing about this is that it works on the returned collection too. So you can interact with the model just as if it were a normal model--but you're really interacting with the specific classes (typeA, typeB).

    评论

报告相同问题?

悬赏问题

  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 linux驱动,linux应用,多线程