Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Mattermost Driver Laravel Package

gnello/php-mattermost-driver

A PHP client for the Mattermost API that makes it easy to send messages, manage channels and users, handle webhooks, and automate team chat workflows from Laravel or any PHP application.

View on GitHub
Deep Wiki
Context7

Getting Started

The driver is framework-agnostic — there is no service provider, facade, or config file. In Laravel you wire it yourself once, as a singleton, and then inject it.

composer require gnello/php-mattermost-driver guzzlehttp/guzzle

Add credentials to config/services.php (note: the v3 base URL includes /api/v3 and no trailing slash):

'mattermost' => [
    'base_url' => env('MATTERMOST_URL', 'https://chat.example.com') . '/api/v3',
    'token'    => env('MATTERMOST_TOKEN'),
    'timeout'  => env('MATTERMOST_TIMEOUT', 10),
],

Bind it in AppServiceProvider::register():

use Gnello\Mattermost\Driver;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;

$this->app->singleton(Driver::class, function () {
    $driver = new Driver(
        new Client(['timeout' => config('services.mattermost.timeout')]),
        new Response(),
        ['base_url' => config('services.mattermost.base_url')]
    );

    if ($token = config('services.mattermost.token')) {
        $driver->setToken($token);
    }

    return $driver;
});

Where to look first: the Driver class getters (getUserModel(), getTeamModel(), getChannelModel(), getPostModel(), getFileModel(), getSystemModel()) and the matching model classes — those are the API surface. The vendor README is thin, so treat the model classes as the documentation.

First real use case: a deployment or exception notifier. Resolve the team and channel by name, then post:

$channel = $driver->getChannelModel()->getChannelByName($teamId, 'town-square');

$driver->getPostModel()->createPost([
    'channel_id' => $channel->getId(),
    'message'    => ":rocket: Deploy `{$sha}` to production finished.",
]);

If you only ever need to send messages, stop here and use a Mattermost incoming webhook instead — a single Http::post() with no token, no session expiry, no stale SDK.

Implementation Patterns

Wrap the driver, don't scatter it. The Driver is a low-level transport; your app should talk to one small service so you can swap it or fake it:

class MattermostNotifier
{
    public function __construct(private Driver $driver) {}

    public function toChannel(string $channelId, string $message, array $attachments = []): void
    {
        try {
            $this->driver->getPostModel()->createPost([
                'channel_id' => $channelId,
                'message'    => $message,
                'props'      => $attachments ? ['attachments' => $attachments] : [],
            ]);
        } catch (RequestException $e) {
            report($e); // never let chat notifications break the request
        }
    }
}

Send from a queued job. Mattermost round-trips are 100–800 ms and can 429. A ShouldQueue job with $tries = 3 and backoff() keeps your HTTP response fast and gives you retries for free.

Cache IDs, not objects. Team IDs, channel IDs and user IDs are stable; resolve them once and Cache::remember("mm:channel:{$teamId}:{$name}", 3600, ...). A notification path that does three API calls to send one message will fall over during an incident — exactly when you need it.

Inbound slash commands / outgoing webhooks fit naturally as a Laravel route. Mattermost posts application/x-www-form-urlencoded with a token; verify it against config with hash_equals, dispatch a job, and return a small JSON payload (response_type, text). Keep the handler under the 3-second response budget by queueing the real work.

File uploads go through the file model with a multipart body (channel_id + files), then you attach the returned file IDs to a post. Uploads are the one place where this driver saves meaningful work over raw Guzzle.

Testing: never hit a real server in the test suite. Bind a Driver backed by Guzzle's MockHandler in a test service provider, or bind a MattermostNotifier fake and assert on expects(). If you go the MockHandler route, keep a couple of real captured JSON fixtures — the v3 response shapes are their own trap.

Multiple workspaces: register named singletons (mattermost.ops, mattermost.support) rather than a single binding; the Driver holds mutable state (the token), so one instance cannot safely serve two servers.

Gotchas and Tips

  • The API version is the headline risk. This package targets Mattermost API v3, and it has not been released since April 2017. Modern Mattermost servers speak v4, and v3 endpoints were dropped in the 5.x line. Before you build anything, curl https://your-server/api/v4/system/ping and check your server version. On a current server, expect 404s and plan on wrapping v4 REST calls yourself or forking the client.
  • Composer friction on modern Laravel. The package's php and guzzlehttp/guzzle constraints are from the PHP 5.6/7.0 era. You may need --ignore-platform-reqs, an inline alias, or a fork. Pin the exact version and add a comment in composer.json explaining why.
  • Tokens expire. v3 auth is session-token based (from login), typically valid ~30 days and invalidated by logout or password change. Personal access tokens are a v4 feature, so with v3 you either persist and refresh the token from a bot account or accept intermittent 401s. Store the token in config/services.php sourced from env, never in the repo.
  • Exception handling is Guzzle's. 4xx/5xx throw GuzzleHttp\Exception\ClientException / ServerException. The body is JSON with id, message, status_code — log message and id, not the whole stack trace, or your logs fill with HTML from the 404-on-wrong-base-URL case.
  • Base URL mistakes produce HTML 404s, not JSON. Missing /api/v3, a trailing slash, or http vs https are the top three causes of "it just doesn't work". Log the effective URL once at boot.
  • The Response instance in the constructor is a prototype. Passing new Response() is boilerplate; do not inspect it afterwards expecting the last call's data. Use the returned model objects.
  • Models are read-only DTOs, not Eloquent. getUser(), getChannel() etc. return package model objects with getters (getId(), getUsername()); the underlying payload is an array. Don't try to persist them directly — map to your own DTOs.
  • 429 handling. Mattermost rate-limits per user. Honour Retry-After; add a Guzzle middleware for retry/backoff rather than sprinkling try/catch around every call.
  • Attachment schema is v3-era. Message attachments and props differ from what current Mattermost renders. Verify formatting against your server, and prefer plain Markdown for anything important.
  • Extension point is Guzzle, not the package. Add logging/retry via HandlerStack and Middleware::log() when constructing the Client. That is also your best debugging tool: dump request/response bodies in local env only.
  • Treat the vendor source as the docs. With 86 stars, a 2017 release, and no maintainer activity, there is no community to Google. Read the model class you need before assuming a method exists.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings