Полиморфные модели Laravel по типам
Мне был нужен лучший способ работы с различными типами моделей на основе одной таблицы базы данных.
В качестве примера приведу таблицу настроек для приложения, способную возвращать различные типы настроек в зависимости от типа столбца строки.
Schema::create('settings', function (Blueprint $table) {
$table->id();
$table->string('type');
$table->text('settings');
$table->timestamps();
});
Столбец type
будет использоваться для определения типа настроек, хранящихся в столбце settings
. Это может быть что-то вроде email
, slack
, sms
и т. д. Столбец settings
представляет собой JSON столбец, хранящий настройки для типа уведомления, такие как адрес электронной или токен и канал для отправки уведомления в slack.
Поскольку значение столбца settings
может состоять из различных типов настроек, понадобился способ обработки этого в приложении. Для каждого типа настроек нужно использовать разные классы, например EmailSetting
, SlackSetting
, SmsSetting
и т. д.
EmailSetting
будет содержать метод getEmail
для получения адреса электронной почты из json-столбца настроек.
<?php
namespace App\Models\Notifications;
use Illuminate\Database\Eloquent\Model;
class EmailSetting extends Model
{
public function getEmail()
{
return $this->settings['email'] ?? '';
}
}
В то время как класс SlackSetting
будет содержать метод getChannel
для получения канала из json-столбца настроек и getToken
для получения API-токена.
<?php
namespace App\Models\Notifications;
use Illuminate\Database\Eloquent\Model;
class SlackSetting extends Model
{
public function getChannel()
{
return $this->settings['channel'] ?? '';
}
public function getToken()
{
return $this->settings['token'] ?? '';
}
}
Полиморфные отношения
Чтобы справиться с этим, я использовал полиморфные отношения Laravel для работы с различными типами настроек. Я создал модель Setting
, использующуюся для работы с различными типами настроек.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Setting extends Model
{
public function notification()
{
return $this->morphTo('type', 'type', 'id');
}
}
Метод notification
— полиморфное отношение, возвращающее правильную модель на основе столбца type
таблицы настроек.
Чтобы указать Laravel, какую модель использовать для каждого типа, необходимо добавить morphMap
в класс AppServiceProvider
.
<?php
namespace App\Providers;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Relation::morphMap([
'email' => EmailSetting::class,
'slack' => SlackSetting::class,
]);
}
}
Метод morphMap
сопоставит типы email
и slack
с классами EmailSetting
и SlackSetting
соответственно.
Теперь при получении параметра из базы данных можно получить доступ к нужной модели на основе столбца type
.
$setting = Setting::find(1);
if($setting->type === 'email') {
$email = $setting->notification->getEmail();
}
if($setting->type === 'slack') {
$channel = $setting->notification->getChannel();
$token = $setting->notification->getToken();
}
Но при этом вы получите ошибку, когда попытаетесь использовать ->notification
, так как он попытается получить доступ к несуществующей таблице email_settings
.
Чтобы исправить это, необходимо указать модели EmailSetting
, какую таблицу использовать методу getTable
.
public function getTable()
{
return 'settings';
}
Это позволит модели EmailSetting
использовать таблицу settings
вместо email_settings
и возвращать правильную модель при использовании настроек уведомлений.
Вот как можно использовать полиморфные модели по типу в Laravel для обработки различных типов настроек в одной таблице базы данных. Это может быть полезным, когда в приложении необходимо обрабатывать различные типы настроек.
Надеюсь, эта статья помогла вам понять, как использовать полиморфные модели по типу в Laravel.