/Laravel

Implementing Notification channel and making package for Laravel

We need to make specific sms service channel for company and developers, here are processing tips.


sybase

Installation Flow

This is private package so you can’t get this.

$ composer require cp/sybase-notification-channel

Navigate to config/services.php adding:

'sybase' => [
    'account' => env('SYBASE_ACCOUNT'),
    'password' => env('SYBASE_PASSWORD'),
    'endpoint' => env('SYBASE_ENDPOINT'),
],

The directory tree

.
└── cp
    └── sybase-notification-channel
        ├── README.md
        ├── composer.json
        ├── composer.lock
        ├── phpunit.xml
        ├── src
        │   ├── Channels
        │   │   └── SybaseChannel.php
        │   ├── Messages
        │   │   └── SybaseMessage.php
        │   └── SybaseChannelServiceProvider.php
        └── tests
            ├── NotificationSybaseChannelTest.php
            └── SybaseMessageTest.php

6 directories, 9 files

Making the directory, for example, packages/cp/sybase-notification-channel. Initial composer package settings, the tips are autoload and autoload-dev to load the classes, and automatic discover the service provider. Next, set mainly properties:

composer.json

{
    "name": "cp/sybase-notification-channel",
    "license": "proprietary",
    ...
    "type": "library",
    ...
    "require": {
        "illuminate/notifications": "^5.7",
        "illuminate/support": "^5.7",
        "guzzlehttp/guzzle": "^6.3"
    },
    "require-dev": {
        "phpunit/phpunit": "^7.5",
        "mockery/mockery": "^1.2",
        "orchestra/testbench": "^3.7"
    },
    "autoload": {
        "psr-4": {
            "Yish\\Notifications\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Yish\\Notifications\\Tests\\": "tests/"
        }
    },
    "extra": {
        "laravel": {
            "providers": [
                "Yish\\Notifications\\SybaseChannelServiceProvider"
            ]
        }
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}

You need to make provider SybaseChannelServiceProvider and move to cp/sybase-notification-channel changing the namespace to Yish\Notifications.

Local testing

Navigate to up root, set repositories path to load it and convenience development: If you want to real test(the mean is sending for real), you can create a new laravel project and package directory put inside, and you need to load via repositories path:

"repositories": [
    {
        "type": "path",
        "url": "./packages/cp/sybase-notification-channel"
    }
],

Execute composer require cp/sybase-notification-channel and composer dump should be seeing Discovered Package: cp/sybase-notification-channel, the mean is discover the service provider.

SybaseChannel Service Provider

use Illuminate\Support\Facades\Notification;
use GuzzleHttp\Client as HttpClient;
use Yish\Notifications\Channels\SybaseChannel;

// register
Notification::extend('sybase', function ($app) {
    return new SybaseChannel(
        new HttpClient,
        $this->app['config']['services.sybase']
    );
});

Why need construct Guzzle client?

We can mock it easily for testing, by the way config properties too.

Configure phpunit.xml

configure specific test directory

<testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./src</directory>
        </whitelist>
    </filter>

SybaseMessage testing and methods

we need to make message to set subject and content, it’s pretty simple

class SybaseMessageTest extends TestCase
{
    ....
    /**
     * @test
     * @group sybase-notification-channel
     */
    public function it_should_be_get_all()
    {
        $expected = new \stdClass();
        $expected->subject = 'Hello';
        $expected->content = 'My name is Yish';

        $message = new SybaseMessage();
        $message->subject('Hello');
        $message->content('My name is Yish');

        $this->assertEquals($expected->subject, $message->subject);
        $this->assertEquals($expected->content, $message->content);
    }
}

Implementing

public $content;

public $subject;

public function content($content)
{
    $this->content = $content;

    return $this;
}

public function subject($subject)
{
    $this->subject = $subject;

    return $this;
}

SybaseChannel testing and methods

set up testing

class NotificationSybaseChannelTest extends TestCase
{
    /**
     * @var Client
     */
    private $guzzleHttp;

    /**
     * @var SybaseChannel
     */
    private $sybaseChannel;

    public function setUp()
    {
        parent::setUp();

        config()->set('services.sybase.account', 'yish');
        config()->set('services.sybase.password', 1234);
        config()->set('services.sybase.endpoint', 'abc.com');

        $this->guzzleHttp = m::mock(Client::class);
        $this->sybaseChannel = new SybaseChannel(
            $this->guzzleHttp, 
            config()->get('services.sybase'));
    }

    public function tearDown()
    {
        m::close();
    }

Next, we put in the test case:

    /**
     * @doesNotPerformAssertions
     */
    public function testCorrectFlowSentToSybase()
    {
        $notification = new NotificationSybaseChannelTestNotification;
        $notifiable = new NotificationSybaseChannelTestNotifiable;

        $this->guzzleHttp->shouldReceive('post')->once();

        $this->sybaseChannel->send($notifiable, $notification);
    }
    ....
}

And dummy Notifiable and Notification

class NotificationSybaseChannelTestNotifiable
{
    use Notifiable;

    public function routeNotificationForSybase()
    {
        return '0912345678';
    }
}

class NotificationSybaseChannelTestNotification extends Notification
{
    public function toSybase($notifiable)
    {
        return (new SybaseMessage)
            ->subject('Come on')
            ->content('Yes, you are come in.');
    }
}

Implementing SybaseChannel

    // Yish\Notifications\Channels\SybaseChannel
    public function __construct(Client $http, array $config)
    {
        $this->http = $http;
        $this->config = $config;
    }

    /**
     * Send the given notification.
     *
     * @param  mixed $notifiable
     * @param  \Illuminate\Notifications\Notification $notification
     * @return void
     */
    public function send($notifiable, Notification $notification)
    {
        if (! $to = $notifiable->routeNotificationFor('sybase', $notification)) {
            return;
        }

        $message = $notification->toSybase($notifiable);

        $this->http->post($this->config['endpoint'], [
            'body' => $this->formatMessage($to, $message),
            'auth' => [$this->config['account'], $this->config['password']]
        ]);
    }

$notifiable->routeNotificationFor('sybase', $notification) will be check if your class use notifiable trait and implement method routeNotificationForSybase it will be replace property.

See in RoutesNotifications.

Running

Notification::route('sybase', $phone)->notify(new \App\Notifications\SendMessage);

Set notification

use Yish\Notifications\Messages\SybaseMessage;
class SendMessage extends Notification
{
  use Queueable;


  public function via($notifiable)
  {
      return ['sybase'];
  }


  public function toSybase($notifiable)
  {
      return (new SybaseMessage)
      ->subject('Hello, world')
      ->content('Yes, bros');
  }
  ....

…or use Notifiable

$guest->notify(new SendMessage('Hello', 'world'));
class Guest extends Authenticatable
{
   use Notifiable;

   public function routeNotificationForSybase($notification)
   {
       return $this->mobile;
   }
}

GitHub - laravel/slack-notification-channel

GitHub - laravel/nexmo-notification-channel

Yish

Yish

The creator of yish.dev

Read More