Как я могу преобразовать / привести родительский объект PHP к дочернему объекту? - PullRequest
0 голосов
/ 30 апреля 2018

Причина

У меня есть устаревшая система со столом, содержащим слизней.

Когда эти записи совпадают, они представляют собой какую-то страницу с идентификатором макета.

Поскольку эти страницы могут иметь разные потребности в ресурсах, это зависит от идентификатора макета, с которым можно объединять таблицы.

Я использую модели Laravel Eloquent.

Мне бы хотелось, чтобы у вас была дочерняя модель, которая содержит отношения, специфичные для макета.

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
}

Однако в моем контроллере, чтобы узнать, какой макет мне нужен, мне уже нужно запросить:

url: / {slug}

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

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

Из-за этого я получаю экземпляр Page, но я хотел бы преобразовать или привести его к экземпляру ArticlePage для загрузки его дополнительных отношений. Как мне этого добиться?

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Вам понадобится заглянуть в Полиморфные отношения в Laravel, чтобы достичь этого. Полиморфная связь позволит вам получить другую модель на основе поля типа . В вашей Slug модели вам понадобится что-то вроде этого:

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

У одного из ваших поставщиков услуг, например, AppServiceProvider вам потребуется предоставить Morph Map , чтобы Laravel отображал определенные идентификаторы в определенные классы моделей. Например:

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

Теперь, когда вы используете отношение page, Laravel проверит тип и вернет вам правильную модель.

Примечание: Я не уверен на 100% в параметрах и т. Д., И я не проверял, но вы должны быть в состоянии понять это из документов.


Если ваш layout_id относится к модели Page, единственное решение, которое я вижу, это добавить метод к вашей модели Page, который способен преобразовать вашу существующую страницу в ArticlePage или другой тип страницы, основанный на свойстве layout_id. Вы должны быть в состоянии попробовать что-то вроде этого:

<?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.');
    }
}

Что это делает, так это ищет отображение на основе вашего свойства layout_id, а затем создает новый класс правильного типа, заполняя его атрибуты теми, которые вы создали на странице. Это должно быть все, что вам нужно, если вы посмотрите на метод Illuminate\Database\Eloquent::newFromBuilder() Laravel, который Laravel вызывает при создании новых экземпляров модели, вы можете увидеть, что происходит и как я получил приведенный выше код. Вы должны иметь возможность просто использовать его так:

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

Это даст вам экземпляр ArticlePage

0 голосов
/ 30 апреля 2018

Насколько я знаю, для этого нет встроенной функции. Но вы могли бы сделать что-то вроде этого.

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

  if ($page->layout_id === 6) {
      $page = ArticlePage::fromPage($page);
  }

А затем на ArticlePage создайте статический метод

public static function fromPage(Page $page)
{
   $articlePage = new self();

   foreach($page->getAttributes() as $key => $attribute) {
       $articlePage->{$key} = $attribute;
   }

   return $articlePage
}

В зависимости от вашего варианта использования может быть разумно создать статический метод, который делает это автоматически на странице отношений () для Slug.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...