›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-mentions
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Mention records
  • Parsing text
  • Resolving targets
  • Synchronization

Operations

  • Scan multiple attributes
  • Use markup mentions
  • Mention groups
  • Querying mentions
  • React to lifecycle events
  • Control synchronization
  • Extend the package

Reference

  • Configuration
  • Public API
  • Published assets
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Mention records
  • Parsing text
  • Resolving targets
  • Synchronization

Operations

  • Scan multiple attributes
  • Use markup mentions
  • Mention groups
  • Querying mentions
  • React to lifecycle events
  • Control synchronization
  • Extend the package

Reference

  • Configuration
  • Public API
  • Published assets
  • Testing
  • Troubleshooting

byrcsc/laravel-mentions · 1.x

Extend the package.

Add a different mention format, target lookup, or mention record model.

Use an extension point when the shipped text formats or column lookup cannot express your application's mention rules. Laravel's container creates the configured classes.

Add a parser

A parser accepts one string and returns MentionCandidate objects. This parser recognizes #topic handles:

namespace App\Mentions;

use Byrcsc\Mentions\Contracts\MentionParser;
use Byrcsc\Mentions\ValueObjects\MentionCandidate;

final class TopicMentionParser implements MentionParser
{
    public function parse(string $text): array
    {
        preg_match_all('/#(?<handle>[A-Za-z0-9_]+)/', $text, $matches);

        return array_map(
            fn (string $handle): MentionCandidate =>
                MentionCandidate::fromHandle("#{$handle}", $handle),
            array_values(array_unique($matches['handle'])),
        );
    }
}

Register and select it:

'default_parser' => 'topics',
'parsers' => [
    'topics' => App\Mentions\TopicMentionParser::class,
],

MentionCandidate::fromHandle() takes the raw matched text first and the handle without its trigger second.

Add a resolver

A resolver receives the remaining candidate batch and returns matched and unmatched values:

namespace App\Mentions;

use App\Models\User;
use Byrcsc\Mentions\Contracts\MentionResolver;
use Byrcsc\Mentions\ValueObjects\ResolutionResult;
use Byrcsc\Mentions\ValueObjects\ResolvedMention;
use Illuminate\Database\Eloquent\Builder;

final class ActiveUserResolver implements MentionResolver
{
    public function resolve(array $candidates): ResolutionResult
    {
        $handles = collect($candidates)
            ->pluck('handle')
            ->filter(fn (mixed $handle): bool => is_string($handle))
            ->map(fn (string $handle): string => mb_strtolower($handle))
            ->unique()
            ->values()
            ->all();

        if ($handles === []) {
            return new ResolutionResult([], $candidates);
        }

        $users = User::query()
            ->where('active', true)
            ->where(function (Builder $query) use ($handles): void {
                foreach ($handles as $handle) {
                    $query->orWhereLike(
                        'username',
                        $handle,
                        caseSensitive: false,
                    );
                }
            })
            ->get()
            ->keyBy(fn (User $user): string => mb_strtolower($user->username));

        $resolved = [];
        $unresolved = [];

        foreach ($candidates as $candidate) {
            $user = $candidate->handle === null
                ? null
                : $users->get(mb_strtolower($candidate->handle));

            if ($user === null) {
                $unresolved[] = $candidate;
            } else {
                $resolved[] = new ResolvedMention($candidate, $user);
            }
        }

        return new ResolutionResult($resolved, $unresolved);
    }
}

Register the resolver by class name:

'resolvers' => [
    'active-users' => App\Mentions\ActiveUserResolver::class,
],

Laravel's container resolves constructor dependencies when your resolver needs application services.

A class-string definition resolves handles but supplies no model mapping for markup IDs. Use the expanded resolver definition when both paths are needed.

Use a custom mention model

Extend the package model:

namespace App\Models;

use Byrcsc\Mentions\Models\Mention as BaseMention;

class Mention extends BaseMention
{
    protected $casts = [
        'created_at' => 'immutable_datetime',
    ];
}

Configure the subclass:

'model' => App\Models\Mention::class,

The configured class must extend Byrcsc\Mentions\Models\Mention. Package relationships and synchronization resolve the base class from the container, so returned records use your subclass.

What to read next

  • Public API for contract signatures and value objects.
  • Configuration for every registration shape.
  • Testing to test custom implementations without application notifications.
PreviousControl synchronizationNextConfiguration
View source

On this page

  1. Add a parser
  2. Add a resolver
  3. Use a custom mention model
  4. What to read next