for example I have model Message
with these columns:
messages
- id
- body
- type
- created_at
- updated_at
And such a controller:
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']));
}
}
and as you see my problem is this long switch
. I tried searching and I found that Polymorphism
could help me to avoid this long switch, but I did not find out how to implement it how much I went and all my searches ended in Polymorphic Relations in Laravel
that was not my answer.
would you help me to do something like this:
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']));
}
}
Update: As I wrote at beginning, It's just an example and switch case block will contain more lines of code.
No need to Polymorphic just make an array like this in your model or config:
$messageColors = [
"info"=>"blue",
.......
]
And then write this:
$color = $messageColors[$message->type];
I would create a class containing consts:
<?php
namespace App\Constants;
class TextColor
{
const INFO = 'blue';
...
const DANGER = 'red';
}
// usage
$color = TextColor::INFO; // 'blue'
However my second advise is to story these colors that correspond to a warning level in a new table (model) with a foreign key on messages.type
to that table.
You can use some sort of 'strategy pattern' to improve your code, creating some services to handle the calculation of the color for each type on message (each strategy), and then one 'delegator' service that decides which service to call, based on the message type...
First you need an interface for all your calculators:
interface ColorCalculatorInterface
{
public function calculateColor(Message $message);
public function getSupportedMessageType();
}
Then one service for each strategy:
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';
}
}
And finally one service that decides which strategy to use based on the message type (this code could be directly into the controller, but it's cleaner as a separate service):
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);
}
}
Now your controller is much thiner!
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...
}
}
Note I'm not a Laravel developer, but a Symfony one! I'm assuming Laravel provides some way to define the delegator service and register all the calculators into it, and finally inject that service into the controller... (Symfony does)
finally, I found my answer from the example on this post and it's working for my situation:
\app\Message.php
class Message extends Model {
public static function color() {
// lots of code here!
return 'grey';
}
}
\app\InfoMessage.php
class InfoMessage extends Message {
public static function color() {
// lots of code here!
return 'blue';
}
}
\app\Http\Controllers\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']));
}
}
thanks for all answers.