duanbai1974 2018-04-30 10:01
浏览 91
已采纳

如何将PHP父对象转换/转换为子对象?

Reason

I got a legacy system with a table containing slugs.

When those records match, it represents some kind of page with a layout ID.

Because these pages can have different resource needs it depends on the layout ID which tables can be joined with.

I use Laravel's Eloquent models.

What I would like is to have a child model that holds the layout specific relations.

class Page extends Model {
    // relation 1, 2, 3 that are always present
}

class ArticlePage extends Page {
    // relation 4 and 5, that are only present on an ArticlePage
}

However in my controller, in order to know which layout I need, I already have to query:

url: /{slug}

$page = Slug::where('slug', $slug)->page;

if ($page->layout_id === 6) {
    //transform $page (Page) to an ArticlePage
}

Because of this I get an instance of Page, but I would like to transform or cast it to an instance of ArticlePage to load it's additional relations. How can I achieve this?

  • 写回答

2条回答 默认 最新

  • dongmaopiao0901 2018-04-30 10:16
    关注

    You'll need to look into Polymorphic relations in Laravel to achieve this. A Polymorphic Relation would allow you to retrieve a different model based on the type of field it is. In your Slug model you would need something like this:

    public function page()
    {
        return $this->morphTo('page', 'layout_id', 'id');
    }
    

    In one of your service providers, e.g. AppServiceProvider you would need to provide a Morph Map to tell Laravel to map certain IDs to certain model classes. For example:

    Relation::morphMap([
        1 => Page::class,
        // ...
        6 => ArticlePage::class,
    ]);
    

    Now, whenever you use the page relation, Laravel will check the type and give you the correct model back.

    Note: I'm not 100% sure on the parameters etc. and I haven't tested but you should be able to work it out from the docs.


    If your layout_id is on the Page model, the only solution I see is to add a method to your Page model that is able to convert your existing page into an ArticlePage, or other page type, based on its layout_id property. You should be able to try something like this:

    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Page extends Model
    {
        const LAYOUT_ARTICLE = 6;
    
        protected $layoutMappings = [
            // Add your other mappings here
            self::LAYOUT_ARTICLE => ArticlePage::class
        ];
    
        public function toLayoutPage()
        {
            $class = $this->layoutMappings[$this->layout_id];
    
            if (class_exists($class)) {
                return (new $class())
                    ->newInstance([], true)
                    ->setRawAttributes($this->getAttributes());
            }
    
            throw new \Exception('Invalid layout.');
        }
    }
    

    What this does is look for a mapping based on your layout_id property, and then it creates a new class of the correct type, filling its attributes with those from the page you're creating from. This should be all you need, if you take a look at Laravel's Illuminate\Database\Eloquent::newFromBuilder() method, which Laravel calls when it creates new model instances, you can see what's going on and how I've gotten the code above. You should be able to just use it like this:

    $page = Slug::where('slug', $slug)
                ->first()
                ->page
                ->toLayoutPage();
    

    That will give you an instance of ArticlePage

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记