Полиморфизм в Ларавеле? - PullRequest
0 голосов
/ 07 мая 2018

например у меня есть модель Message с этими столбцами:

messages
- id
- body
- type
- created_at
- updated_at

И такой контроллер:

class MessageController extends Controller
{

    /**
     * Display the specified resource.
     *
     * @param  \App\Message  $message
     * @return \Illuminate\Http\Response
     */
    public function show(Message $message)
    {
        switch ($message->type) {
            case 'info':
                $color = 'blue';
                // updated - lots of code here!
                break;
            case 'warning':
                $color = 'yellow';
                // updated - lots of code here!
                break;

            .
            .
            .

            case 'danger':
                $color = 'red';
                // updated - lots of code here!
                break;
            default:
                $color = 'gray';
                // updated - lots of code here!
        }
        return view('messages.show',compact(['message','color']));
    }

}

и, как вы видите, моя проблема в этом switch. Я попытался выполнить поиск и обнаружил, что Polymorphism может помочь мне избежать этого длинного переключения, но я не понял, как реализовать его, сколько я прошел, и все мои поиски закончились Polymorphic Relations in Laravel, что не было моим ответом.

Не могли бы вы помочь мне сделать что-то вроде этого:

class MessageController extends Controller
{

    /**
     * Display the specified resource.
     *
     * @param  \App\Message  $message
     * @return \Illuminate\Http\Response
     */
    public function show(Message $message)
    {
        $color = $message->[something?]->color();
        return view('messages.show',compact(['message','color']));
    }

}

Обновление: Как я писал в начале, это всего лишь пример, и блок регистра переключателей будет содержать больше строк кода.

Ответы [ 4 ]

0 голосов
/ 12 мая 2018

наконец, я нашел свой ответ из примера на этом посте , и он работает для моей ситуации:

\ приложение \ message.php

class Message extends Model {

  public static function color() {
    // lots of code here!
    return 'grey';
  }

}

\ приложение \ InfoMessage.php

class InfoMessage extends Message {

  public static function color() {
    // lots of code here!
    return 'blue';
  }

}

\ приложение \ Http \ Контроллеры \ MessageController.php

class MessageController extends Controller {

  public function show(Message $message) {
    $color = $message->type ? $message->type::color() : $message->color();
    // $message->type will be something like '\App\InfoMessage'
    // so $message->type::color() will be equal to \App\InfoMessage::color()
    return view('messages.show',compact(['message','color']));
  }

}

спасибо за все ответы.

0 голосов
/ 07 мая 2018

Я бы создал класс, содержащий константы:

<?php

namespace App\Constants;

class TextColor
{
    const INFO = 'blue';
    ...
    const DANGER = 'red';
}

// usage
$color = TextColor::INFO; // 'blue'

Однако мой второй совет - добавить эти цвета, которые соответствуют уровню предупреждения, в новой таблице (модели) с внешним ключом messages.type к этой таблице.

0 голосов
/ 10 мая 2018

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

Для начала вам нужен интерфейс для всех ваших калькуляторов:

interface ColorCalculatorInterface
{
    public function calculateColor(Message $message);

    public function getSupportedMessageType();
}

Тогда один сервис для каждой стратегии:

class InfoColorCalculator implements ColorCalculatorInterface
{
    public function getSupportedMessageType()
    {
        return 'info';    
    }

    public function calculateColor(Message $message) 
    {
        // lots of code here!
        return 'blue';
    }
}

class WarningColorCalculator implements ColorCalculatorInterface
{
    public function getSupportedMessageType()
    {
        return 'warning';    
    }

    public function calculateColor(Message $message) 
    {
        // lots of code here!
        return 'yellow';
    }
}

// More calculators...

class DefaultColorCalculator implements ColorCalculatorInterface
{
    public function getSupportedMessageType()
    {
        return 'default';    
    }

    public function calculateColor(Message $message) 
    {
        // lots of code here!
        return 'grey';
    }
}

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

class ColorCalculator 
{

    private $calculators = [];
    private $defaultCalculator;

    public function setDefaultColorCalculator(ColorCalculatorInterface $calculator)
    {
        $this->defaultCalculator = $calculator;
    }

    public function registerColorCalculator(ColorCalculatorInterface $calculator)
    {
        $this->calculators[$calculator->getSupportedMessageType()] = $calculator;
    }

    public function calculateColor(Message $message)
    {
        if (array_key_exists($message->getType(), $this->calculators)) {
            $calculator = $this->calculators[$message->getType()];
        } else {
            $calculator = $this->defaultCalculator;
        }

        return $calculator->calculateColor($message);
    }
}

Теперь ваш контроллер намного тоньше!

class MessageController extends Controller
{
    /** @var ColorCalculator */
    private $calculator;

    public function show(Message $message)
    {
        $color = $this->calculator->calculateColor($message);

        // do what you want with your color...
    }
}

Заметьте, я не разработчик Laravel, а разработчик Symfony! Я предполагаю, что Laravel предоставляет какой-то способ определить службу делегата и зарегистрировать в ней все калькуляторы, и, наконец, внедрить эту службу в контроллер ... (Symfony делает)

0 голосов
/ 07 мая 2018

Polymorphic не нужно, просто создайте массив, подобный этому, в вашей модели или конфигурации:

    $messageColors = [
        "info"=>"blue",
        .......
    ]

А затем напишите это:

    $color = $messageColors[$message->type];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...