Skip to content

Latest commit

 

History

History
172 lines (141 loc) · 3.44 KB

eloquent-username-mentions.md

File metadata and controls

172 lines (141 loc) · 3.44 KB

Username Mentions

Usage

$post = new Post($request->validated());
$post->user()->associate($request->user());
$post->save();
$post->getMentionedUsers()->each(fn($user)=>$user->notify(new MentionNotification($post)));

Blade Rendering

<p>{!! $post->compileMentions() !!}</p>

User Model Method

/**
 * Find by username
 * @param string ...$usernames
 * @return EloquentCollection
 */
public static function findByUsername(...$usernames): EloquentCollection
{
    return static::query()->whereIn('username', $usernames)->get();
}

Configure Model

use App\Concerns\HasMentions;

class Post extends Model
{
    use HasMentions;
    
    /**
     * Parse Mentions from Attribute
     * @var string
     */
    public string $mentionable = 'content';

Trait

<?php declare(strict_types=1);

namespace App\Concerns;

use App\User;
use App\Services\Mentions;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Collection;

trait HasMentions
{

    //public string $mentionable = 'content';

    /**
     * Compile Username Mentions to Raw Blade Syntax.
     * @return string
     */
    public function compileMentions(): string
    {
        return Mentions::make(nl2br($this->getAttribute($this->mentionable)))->compile();
    }

    /**
     * Get Username Mentions Collection.
     * @return Collection
     */
    public function getMentions(): Collection
    {
        return Mentions::make($this->getAttribute($this->mentionable))->toCollection();
    }

    /**
     * Find Mentioned Users by Username.
     * @return EloquentCollection
     */
    public function getMentionedUsers(): EloquentCollection
    {
        return User::findByUsername(...$this->getMentions()->take(100)->toArray());
    }
}

Service

<?php declare(strict_types=1);

namespace App\Services;

use Illuminate\Support\Str;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Blade;

class Mentions
{
    const MENTIONS_REGEX = "(@(?P<name>[a-zA-Z\-_]+))";

    private string $value;

    /**
     * Mentions constructor.
     * @param string $value
     */
    public function __construct(string $value)
    {
        $this->value = $value;
    }

    /**
     * Make Instance of Self.
     * @param string $value
     * @return static
     */
    public static function make(string $value): self
    {
        return app(static::class, ['value' => $value]);
    }

    /**
     * Get the mentions as a collection.
     * @return Collection
     */
    public function toCollection(): Collection
    {
        return Str::of($this->value)->matchAll(static::MENTIONS_REGEX);
    }

    /**
     * Compile the blade template for rendering.
     * @return string
     */
    public function compile(): string
    {
        return Blade::compileString($this->compileTemplate());
    }

    /**
     * Compile the string to a blade template.
     * @return string
     */
    protected function compileTemplate(): string
    {
        return (string) Str::of($this->value)->replaceMatches(static::MENTIONS_REGEX,
            fn($match) => $this->template($match['name'])
        );
    }

    /**
     * Wrap the name with the blade template tags.
     * @param $username
     * @return string
     * @throws Throwable
     */
    protected function template($username): string
    {
        return view('components.posts.mention', [
            'username' => $username
        ])->render();
    }
}