3neti / laravel-model-channel
A package to enable assigning communication channels to Eloquent models.
Requires
- php: ^8.2
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
- propaganistas/laravel-phone: ^6.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.8
README
A schema-light Laravel capability package for attaching delivery and communication channels to Eloquent models through a polymorphic channels table.
Why this package exists
This package lets a model expose capabilities like mobile or webhook delivery without requiring host apps to add direct columns such as users.mobile or users.webhook.
Channels are stored in the package-owned morph table, keeping your application schema clean and flexible.
Installation
composer require 3neti/laravel-model-channel php artisan migrate
Supported Channel Types
Out of the box, the package supports:
mobile(normalized to E.164 without+)webhook(validated URL)telegram(numeric ID)whatsapp(phone-based)viber(phone-based)
All channels are validated via enum-backed rules.
Basic usage
use Illuminate\Database\Eloquent\Model; use LBHurtado\ModelChannel\Contracts\HasMobileChannel; use LBHurtado\ModelChannel\Contracts\HasWebhookChannel; use LBHurtado\ModelChannel\Traits\HasChannels; class User extends Model implements HasMobileChannel, HasWebhookChannel { use HasChannels; }
Explicit capability API
Mobile
$user->setMobileChannel('09171234567'); $user->getMobileChannel(); // 639171234567 $user->hasMobileChannel(); // true
Accepted formats:
$user->setMobileChannel('09171234567'); $user->setMobileChannel('0917 123 4567'); $user->setMobileChannel('639171234567'); $user->setMobileChannel('+639171234567'); $user->setMobileChannel('+63 (917) 123-4567');
All normalize to:
639171234567
Webhook
$user->setWebhookChannel('https://example.com/webhook'); $user->getWebhookChannel(); // https://example.com/webhook $user->hasWebhookChannel(); // true
Generic API
$user->setChannel('webhook', 'https://example.com/webhook'); $user->getChannel('webhook'); $user->hasChannel('webhook');
Using enum:
use LBHurtado\ModelChannel\Enums\Channel; $user->setChannel(Channel::WEBHOOK, 'https://example.com/webhook');
Delete a channel:
$user->setChannel(Channel::WEBHOOK, null); $user->setChannel(Channel::WEBHOOK, '');
Magic properties (backward compatibility)
$user->mobile = '09171234567'; $user->mobile; // 639171234567 $user->getMobileChannel(); // 639171234567
Additional helpers
Telegram
$user->setTelegramChannel('123456789'); $user->getTelegramChannel(); $user->hasTelegramChannel();
$user->setWhatsappChannel('09171234567'); $user->getWhatsappChannel(); $user->hasWhatsappChannel();
Viber
$user->setViberChannel('09171234567'); $user->getViberChannel(); $user->hasViberChannel();
Finders
User::findByMobile('09171234567'); User::findByWebhook('https://example.com/webhook'); User::findByChannel('telegram', '123456789');
Mobile finder supports multiple formats.
Performance & Caching
Database Indexing (Recommended)
For optimal performance, especially for findByMobile() and findByChannel(), add indexes:
$table->index(['name', 'value']); $table->index(['model_type', 'model_id', 'name']);
Lookup Caching (Optional)
Caching is designed for finder methods only, not accessor reads.
Supported cached operations:
findByMobile()findByWebhook()findByChannel()(for configured channels)
Example config:
'cache' => [ 'enabled' => true, 'ttl' => 600, 'channels' => ['mobile', 'webhook'], ]
Cache Behavior
- caches model IDs only (not full models)
- caches misses to prevent repeated DB queries
- automatically invalidates on update or delete
- does NOT cache accessor methods like
getMobileChannel()
External package integration
use LBHurtado\ModelChannel\Contracts\HasMobileChannel; function sendOtp(HasMobileChannel $user) { $mobile = $user->getMobileChannel(); }
Storage model
No schema changes required.
All data is stored in the polymorphic channels table.