Deploy 1.x docs
This commit is contained in:
150
raw/essentials/attachments.md
Normal file
150
raw/essentials/attachments.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# Attachments
|
||||
|
||||
> File uploads for comments.
|
||||
|
||||
## Overview
|
||||
|
||||
Comments support file attachments for both images and documents. Images are displayed inline within the comment body, while documents appear as downloadable links.
|
||||
|
||||
## Configuration
|
||||
|
||||
```php
|
||||
// config/comments.php
|
||||
'attachments' => [
|
||||
'enabled' => true,
|
||||
'disk' => 'public',
|
||||
'max_size' => 10240, // KB (10 MB)
|
||||
'allowed_types' => [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'application/pdf',
|
||||
'text/plain',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Key
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Default
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
enabled
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<code>
|
||||
true
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Show/hide the attachment upload UI
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
disk
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<code>
|
||||
'public'
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Laravel filesystem disk for storage
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
max_size
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<code>
|
||||
10240
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Maximum file size in kilobytes
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
allowed_types
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
images, pdf, text, word
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Array of allowed MIME types
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Disabling Attachments
|
||||
|
||||
```php
|
||||
'attachments' => [
|
||||
'enabled' => false,
|
||||
],
|
||||
```
|
||||
|
||||
This removes the file upload UI from the comment form entirely.
|
||||
|
||||
## Storage
|
||||
|
||||
Attachments are stored via Livewire's file upload mechanism. Each attachment record tracks:
|
||||
|
||||
- `file_path` -- Path on the configured disk
|
||||
- `original_name` -- Original filename for display
|
||||
- `mime_type` -- MIME type for rendering decisions
|
||||
- `size` -- File size in bytes
|
||||
- `disk` -- Storage disk name
|
||||
|
||||
When a comment is deleted, its attachments are cascade deleted from the database. The physical files are removed from the disk.
|
||||
|
||||
## Helper Methods
|
||||
|
||||
The `CommentAttachment` model provides:
|
||||
|
||||
```php
|
||||
$attachment->isImage(); // Check if attachment is an image
|
||||
$attachment->url(); // Get the storage URL
|
||||
$attachment->formattedSize(); // Human-readable size (e.g., "2.5 MB")
|
||||
```
|
||||
169
raw/essentials/authorization.md
Normal file
169
raw/essentials/authorization.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# Authorization
|
||||
|
||||
> Control who can create, edit, delete, and reply to comments.
|
||||
|
||||
## Default Policy
|
||||
|
||||
The built-in `CommentPolicy` provides sensible defaults:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Method
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Default
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
viewAny()
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<code>
|
||||
true
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Everyone can view comments
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
create()
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<code>
|
||||
true
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Everyone can create comments
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
update()
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Owner only
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Only the comment author can edit
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
delete()
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Owner only
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Only the comment author can delete
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
reply()
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Depth check
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Can reply if <code>
|
||||
max_depth
|
||||
</code>
|
||||
|
||||
not exceeded
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Custom Policy
|
||||
|
||||
Create your own policy to customize authorization:
|
||||
|
||||
```php
|
||||
namespace App\Policies;
|
||||
|
||||
use Relaticle\Comments\Comment;
|
||||
use Relaticle\Comments\Contracts\Commenter;
|
||||
|
||||
class CustomCommentPolicy
|
||||
{
|
||||
public function viewAny(Commenter $user): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function create(Commenter $user): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function update(Commenter $user, Comment $comment): bool
|
||||
{
|
||||
return $comment->user_id === $user->getKey()
|
||||
&& $comment->user_type === $user->getMorphClass();
|
||||
}
|
||||
|
||||
public function delete(Commenter $user, Comment $comment): bool
|
||||
{
|
||||
return $comment->user_id === $user->getKey()
|
||||
|| $user->hasRole('admin');
|
||||
}
|
||||
|
||||
public function reply(Commenter $user, Comment $comment): bool
|
||||
{
|
||||
return $comment->canReply();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Register it in your config:
|
||||
|
||||
```php
|
||||
// config/comments.php
|
||||
'policy' => App\Policies\CustomCommentPolicy::class,
|
||||
```
|
||||
|
||||
## How Authorization Works
|
||||
|
||||
The Livewire components check the policy before rendering action buttons. Edit and delete buttons only appear for authorized users. Reply buttons are hidden when the thread has reached the configured `max_depth`.
|
||||
|
||||
The policy is registered automatically by the service provider using Laravel's Gate system.
|
||||
184
raw/essentials/configuration.md
Normal file
184
raw/essentials/configuration.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# Configuration
|
||||
|
||||
> Configure threading, reactions, mentions, attachments, notifications, and more.
|
||||
|
||||
Publish the configuration file:
|
||||
|
||||
```bash
|
||||
php artisan vendor:publish --tag=comments-config
|
||||
```
|
||||
|
||||
This creates `config/comments.php` with all available options.
|
||||
|
||||
## Table Name
|
||||
|
||||
```php
|
||||
'tables' => [
|
||||
'comments' => 'comments',
|
||||
],
|
||||
```
|
||||
|
||||
Change the table name if it conflicts with your application.
|
||||
|
||||
## Models
|
||||
|
||||
```php
|
||||
'models' => [
|
||||
'comment' => \Relaticle\Comments\Comment::class,
|
||||
],
|
||||
|
||||
'commenter' => [
|
||||
'model' => \App\Models\User::class,
|
||||
],
|
||||
```
|
||||
|
||||
Override the Comment model to add custom behavior. The commenter model defines which class represents the user who comments.
|
||||
|
||||
## Policy
|
||||
|
||||
```php
|
||||
'policy' => \Relaticle\Comments\Policies\CommentPolicy::class,
|
||||
```
|
||||
|
||||
See the [Authorization](/essentials/authorization) page for customization details.
|
||||
|
||||
## Threading
|
||||
|
||||
```php
|
||||
'threading' => [
|
||||
'max_depth' => 2,
|
||||
],
|
||||
```
|
||||
|
||||
Controls how many levels of nested replies are allowed. A depth of `2` means top-level comments and one level of replies. Set to `1` to disable replies entirely.
|
||||
|
||||
## Pagination
|
||||
|
||||
```php
|
||||
'pagination' => [
|
||||
'per_page' => 10,
|
||||
],
|
||||
```
|
||||
|
||||
Number of comments loaded initially and per "Load More" click.
|
||||
|
||||
## Reactions
|
||||
|
||||
```php
|
||||
'reactions' => [
|
||||
'emoji_set' => [
|
||||
'thumbs_up' => "\u{1F44D}",
|
||||
'heart' => "\u{2764}\u{FE0F}",
|
||||
'celebrate' => "\u{1F389}",
|
||||
'laugh' => "\u{1F604}",
|
||||
'thinking' => "\u{1F914}",
|
||||
'sad' => "\u{1F622}",
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
Customize the available emoji reactions. Keys are used as identifiers in the database, values are the displayed emoji characters.
|
||||
|
||||
## Mentions
|
||||
|
||||
```php
|
||||
'mentions' => [
|
||||
'resolver' => \Relaticle\Comments\Mentions\DefaultMentionResolver::class,
|
||||
'max_results' => 5,
|
||||
],
|
||||
```
|
||||
|
||||
The resolver handles searching for users during @mention autocomplete. See the [Mentions](/essentials/mentions) page for creating a custom resolver.
|
||||
|
||||
## Editor Toolbar
|
||||
|
||||
```php
|
||||
'editor' => [
|
||||
'toolbar' => [
|
||||
['bold', 'italic', 'strike', 'link'],
|
||||
['bulletList', 'orderedList'],
|
||||
['codeBlock'],
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
Defines which formatting buttons appear in the comment editor. Groups create visual separators in the toolbar.
|
||||
|
||||
## Notifications
|
||||
|
||||
```php
|
||||
'notifications' => [
|
||||
'channels' => ['database'],
|
||||
'enabled' => true,
|
||||
],
|
||||
```
|
||||
|
||||
Add `'mail'` to the channels array to send email notifications. Set `enabled` to `false` to disable all notifications.
|
||||
|
||||
## Subscriptions
|
||||
|
||||
```php
|
||||
'subscriptions' => [
|
||||
'auto_subscribe' => true,
|
||||
],
|
||||
```
|
||||
|
||||
When enabled, users are automatically subscribed to a thread when they create a comment or are mentioned. They receive notifications for subsequent replies.
|
||||
|
||||
## Attachments
|
||||
|
||||
```php
|
||||
'attachments' => [
|
||||
'enabled' => true,
|
||||
'disk' => 'public',
|
||||
'max_size' => 10240, // KB
|
||||
'allowed_types' => [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'application/pdf',
|
||||
'text/plain',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
Controls file upload behavior. Set `enabled` to `false` to remove the attachment UI entirely. The `max_size` is in kilobytes (default 10 MB).
|
||||
|
||||
## Broadcasting
|
||||
|
||||
```php
|
||||
'broadcasting' => [
|
||||
'enabled' => false,
|
||||
'channel_prefix' => 'comments',
|
||||
],
|
||||
```
|
||||
|
||||
When enabled, comment events are broadcast on private channels using the format `{prefix}.{commentable_type}.{commentable_id}`. Requires Laravel Echo and a broadcasting driver.
|
||||
|
||||
## Polling
|
||||
|
||||
```php
|
||||
'polling' => [
|
||||
'interval' => '10s',
|
||||
],
|
||||
```
|
||||
|
||||
When broadcasting is disabled, the Livewire component polls for new comments at this interval. Set to `null` to disable polling.
|
||||
|
||||
## Custom User Resolution
|
||||
|
||||
Override how the authenticated user is resolved:
|
||||
|
||||
```php
|
||||
use Relaticle\Comments\Config;
|
||||
|
||||
// In AppServiceProvider::boot()
|
||||
Config::resolveAuthenticatedUserUsing(function () {
|
||||
return auth()->user();
|
||||
});
|
||||
```
|
||||
|
||||
This is useful for multi-guard applications or custom authentication flows.
|
||||
746
raw/essentials/database-schema.md
Normal file
746
raw/essentials/database-schema.md
Normal file
@@ -0,0 +1,746 @@
|
||||
# Database Schema
|
||||
|
||||
> Tables, relationships, and indexes used by the Comments package.
|
||||
|
||||
## Tables
|
||||
|
||||
Five tables are created by the package migrations.
|
||||
|
||||
### comments
|
||||
|
||||
The main comments table with polymorphic relationships and threading support.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Column
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Type
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Primary key
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
commentable_type
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Polymorphic model type
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
commentable_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Polymorphic model ID
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
user_type
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Commenter model type
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
user_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Commenter model ID
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
parent_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint (nullable)
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Parent comment for replies
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
body
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
text
|
||||
</td>
|
||||
|
||||
<td>
|
||||
HTML comment content
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
edited_at
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
timestamp (nullable)
|
||||
</td>
|
||||
|
||||
<td>
|
||||
When the comment was last edited
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
deleted_at
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
timestamp (nullable)
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Soft delete timestamp
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
created_at
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
timestamp
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
updated_at
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
timestamp
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
**Indexes:** `(commentable_type, commentable_id, parent_id)`
|
||||
|
||||
### comment_reactions
|
||||
|
||||
Tracks emoji reactions per user per comment.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Column
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Type
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Primary key
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
comment_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Foreign key to comments
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
user_type
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Reactor model type
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
user_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Reactor model ID
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
reaction
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Reaction key (e.g., <code>
|
||||
thumbs_up
|
||||
</code>
|
||||
|
||||
)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
created_at
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
timestamp
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
**Unique constraint:** `(comment_id, user_id, user_type, reaction)`
|
||||
|
||||
### comment_mentions
|
||||
|
||||
Tracks @mentioned users per comment.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Column
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Type
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Primary key
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
comment_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Foreign key to comments
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
user_type
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Mentioned user model type
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
user_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Mentioned user model ID
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
created_at
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
timestamp
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
**Unique constraint:** `(comment_id, user_id, user_type)`
|
||||
|
||||
### comment_subscriptions
|
||||
|
||||
Tracks which users are subscribed to comment threads on specific models.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Column
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Type
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Primary key
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
commentable_type
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Subscribed model type
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
commentable_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Subscribed model ID
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
user_type
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Subscriber model type
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
user_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Subscriber model ID
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
created_at
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
timestamp
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
**Unique constraint:** `(commentable_type, commentable_id, user_type, user_id)`
|
||||
|
||||
### comment_attachments
|
||||
|
||||
Stores file attachment metadata for comments.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Column
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Type
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Primary key
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
comment_id
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Foreign key to comments
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
file_path
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Path on the storage disk
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
original_name
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Original uploaded filename
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
mime_type
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
File MIME type
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
size
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
bigint
|
||||
</td>
|
||||
|
||||
<td>
|
||||
File size in bytes
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
disk
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
string
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Laravel filesystem disk
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
created_at
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
timestamp
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
updated_at
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
timestamp
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Relationships
|
||||
|
||||
```text
|
||||
Commentable Model (e.g., Project)
|
||||
└── comments (morphMany)
|
||||
├── user (morphTo → User)
|
||||
├── parent (belongsTo → Comment)
|
||||
├── replies (hasMany → Comment)
|
||||
├── reactions (hasMany → CommentReaction)
|
||||
├── attachments (hasMany → CommentAttachment)
|
||||
└── mentions (morphToMany → User)
|
||||
```
|
||||
|
||||
All relationships are polymorphic, allowing the same comment system to work across any number of models in your application.
|
||||
120
raw/essentials/mentions.md
Normal file
120
raw/essentials/mentions.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Mentions
|
||||
|
||||
> User @mentions with autocomplete and notification support.
|
||||
|
||||
## How Mentions Work
|
||||
|
||||
Type `@` in the comment editor to trigger user autocomplete. Select a user to insert a mention. When the comment is saved, the `MentionParser` extracts mentions and:
|
||||
|
||||
1. Syncs mention records in the `comment_mentions` table
|
||||
2. Dispatches a `UserMentioned` event for each newly mentioned user
|
||||
3. The `SendUserMentionedNotification` listener sends notifications
|
||||
4. If auto-subscribe is enabled, mentioned users are subscribed to the thread
|
||||
|
||||
## Default Resolver
|
||||
|
||||
The `DefaultMentionResolver` searches the commenter model by name:
|
||||
|
||||
```php
|
||||
// Searches: User::where('name', 'like', "{$query}%")
|
||||
// Limited to: config('comments.mentions.max_results') results
|
||||
```
|
||||
|
||||
## Custom Mention Resolver
|
||||
|
||||
Implement the `MentionResolver` interface to customize user search behavior:
|
||||
|
||||
```php
|
||||
namespace App\Comments;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Relaticle\Comments\Contracts\MentionResolver;
|
||||
|
||||
class TeamMentionResolver implements MentionResolver
|
||||
{
|
||||
public function search(string $query): Collection
|
||||
{
|
||||
return User::query()
|
||||
->where('team_id', auth()->user()->team_id)
|
||||
->where('name', 'like', "{$query}%")
|
||||
->limit(config('comments.mentions.max_results'))
|
||||
->get();
|
||||
}
|
||||
|
||||
public function resolveByNames(array $names): Collection
|
||||
{
|
||||
return User::query()
|
||||
->where('team_id', auth()->user()->team_id)
|
||||
->whereIn('name', $names)
|
||||
->get();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Register it in your config:
|
||||
|
||||
```php
|
||||
// config/comments.php
|
||||
'mentions' => [
|
||||
'resolver' => App\Comments\TeamMentionResolver::class,
|
||||
'max_results' => 5,
|
||||
],
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Key
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Default
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
mentions.resolver
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<code>
|
||||
DefaultMentionResolver::class
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
User search implementation
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
mentions.max_results
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<code>
|
||||
5
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Maximum autocomplete results
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
213
raw/essentials/notifications.md
Normal file
213
raw/essentials/notifications.md
Normal file
@@ -0,0 +1,213 @@
|
||||
# Notifications
|
||||
|
||||
> Comment notifications, subscriptions, and real-time updates.
|
||||
|
||||
## Notification Types
|
||||
|
||||
Two notification classes are included:
|
||||
|
||||
### CommentRepliedNotification
|
||||
|
||||
Sent to all thread subscribers when a new comment or reply is posted. The comment author is excluded from receiving their own notification.
|
||||
|
||||
### UserMentionedNotification
|
||||
|
||||
Sent to a user when they are @mentioned in a comment. Self-mentions are ignored.
|
||||
|
||||
## Channels
|
||||
|
||||
```php
|
||||
// config/comments.php
|
||||
'notifications' => [
|
||||
'channels' => ['database'],
|
||||
'enabled' => true,
|
||||
],
|
||||
```
|
||||
|
||||
Available channels: `'database'` and `'mail'`. Add both to send email notifications alongside database notifications:
|
||||
|
||||
```php
|
||||
'notifications' => [
|
||||
'channels' => ['database', 'mail'],
|
||||
'enabled' => true,
|
||||
],
|
||||
```
|
||||
|
||||
## Subscriptions
|
||||
|
||||
Users can subscribe to comment threads on any commentable model. Subscribers receive notifications when new comments are posted.
|
||||
|
||||
### Auto-Subscribe
|
||||
|
||||
```php
|
||||
'subscriptions' => [
|
||||
'auto_subscribe' => true,
|
||||
],
|
||||
```
|
||||
|
||||
When enabled:
|
||||
|
||||
- Users are auto-subscribed when they post a comment
|
||||
- Users are auto-subscribed when they are @mentioned
|
||||
|
||||
### Manual Subscription
|
||||
|
||||
Users can toggle their subscription using the subscribe/unsubscribe button in the comments UI.
|
||||
|
||||
### Programmatic Access
|
||||
|
||||
```php
|
||||
use Relaticle\Comments\CommentSubscription;
|
||||
|
||||
// Check subscription status
|
||||
CommentSubscription::isSubscribed($commentable, $user);
|
||||
|
||||
// Subscribe/unsubscribe
|
||||
CommentSubscription::subscribe($commentable, $user);
|
||||
CommentSubscription::unsubscribe($commentable, $user);
|
||||
|
||||
// Get all subscribers for a commentable
|
||||
$subscribers = CommentSubscription::subscribersFor($commentable);
|
||||
```
|
||||
|
||||
## Events
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Event
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Trigger
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Broadcasts
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
CommentCreated
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
New comment or reply
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Yes
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
CommentUpdated
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Comment edited
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Yes
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
CommentDeleted
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Comment soft-deleted
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Yes
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
CommentReacted
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Reaction added/removed
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Yes
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
UserMentioned
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
User @mentioned
|
||||
</td>
|
||||
|
||||
<td>
|
||||
No
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Real-time Updates
|
||||
|
||||
### Broadcasting
|
||||
|
||||
Enable broadcasting for instant updates across browser sessions:
|
||||
|
||||
```php
|
||||
// config/comments.php
|
||||
'broadcasting' => [
|
||||
'enabled' => true,
|
||||
'channel_prefix' => 'comments',
|
||||
],
|
||||
```
|
||||
|
||||
Events are broadcast on private channels: `{prefix}.{commentable_type}.{commentable_id}`
|
||||
|
||||
This requires Laravel Echo and a broadcasting driver (Pusher, Ably, etc.) configured in your application.
|
||||
|
||||
### Polling Fallback
|
||||
|
||||
When broadcasting is disabled, the Livewire component polls for updates:
|
||||
|
||||
```php
|
||||
'polling' => [
|
||||
'interval' => '10s',
|
||||
],
|
||||
```
|
||||
|
||||
Set to `null` to disable polling entirely.
|
||||
|
||||
## Disabling Notifications
|
||||
|
||||
```php
|
||||
'notifications' => [
|
||||
'enabled' => false,
|
||||
],
|
||||
```
|
||||
|
||||
This disables all notification dispatching. Subscriptions and events still work, but no notifications are sent.
|
||||
153
raw/essentials/reactions.md
Normal file
153
raw/essentials/reactions.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Reactions
|
||||
|
||||
> Emoji reactions on comments.
|
||||
|
||||
## Default Reactions
|
||||
|
||||
Six emoji reactions are available out of the box:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Key
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Emoji
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Label
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
thumbs_up
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
:thumbsup:
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Like
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
heart
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
❤️
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Love
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
celebrate
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
🎉
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Celebrate
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
laugh
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
😄
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Laugh
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
thinking
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
🤔
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Thinking
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
sad
|
||||
</code>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
😢
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Sad
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## How Reactions Work
|
||||
|
||||
- Each user can add one reaction of each type per comment
|
||||
- Clicking the same reaction again removes it (toggle behavior)
|
||||
- The reaction summary shows which users reacted with each emoji
|
||||
- A `CommentReacted` event is dispatched with `action: 'added'` or `'removed'`
|
||||
|
||||
## Customizing Reactions
|
||||
|
||||
Override the emoji set in your config:
|
||||
|
||||
```php
|
||||
// config/comments.php
|
||||
'reactions' => [
|
||||
'emoji_set' => [
|
||||
'thumbs_up' => "\u{1F44D}",
|
||||
'thumbs_down' => "\u{1F44E}",
|
||||
'heart' => "\u{2764}\u{FE0F}",
|
||||
'fire' => "\u{1F525}",
|
||||
'eyes' => "\u{1F440}",
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
Keys are stored in the database. If you change a key, existing reactions with the old key will no longer display.
|
||||
|
||||
## Storage
|
||||
|
||||
Reactions are stored in the `comment_reactions` table with a unique constraint on `(comment_id, user_id, user_type, reaction)`, ensuring one reaction of each type per user per comment.
|
||||
Reference in New Issue
Block a user