Flagable

v1.0

Laravel Flagging System

A flexible and robust Laravel package that provides comprehensive flagging functionality for Eloquent models with polymorphic relationships and sophisticated multi-table architecture.

Key Features

Everything you need for a complete flagging system in Laravel

Flexible Flagging

Any model can flag any other model with polymorphic relationships

Multiple Flag Types

Support for like, follow, favorite, bookmark, upvote, downvote, and custom types

Sophisticated Architecture

Four-table design for optimal performance and flexibility

Installation

Get started with Flagable in just a few steps

Requirements

PHP 8.0 or higher
Laravel 9.0, 10.0, 11.0, or 12.0
1

Install via Composer

composer require sowailem/flagable
2

Run Migrations

The package will automatically register its service provider and facade through Laravel's auto-discovery feature.

php artisan migrate
3

Seed Default Flag Types (Optional)

To populate the database with default flag types (like, follow, favorite, bookmark, upvote, downvote):

php artisan db:seed --class="Sowailem\Flagable\Database\Seeders\FlagTypeSeeder"

Usage Guide

Learn how to implement flagging in your Laravel models

Quick Start

1. Make Models Flaggable

Add the Flagable trait to models that can be flagged:

<?php

use Sowailem\Flagable\Traits\Flagable;

class Post extends Model
{
    use Flagable;
    
    // Your model code...
}

2. Enable Models to Flag

Add the CanFlag trait to models that can flag others:

<?php

use Sowailem\Flagable\Traits\CanFlag;

class User extends Model
{
    use CanFlag;
    
    // Your model code...
}

Basic Operations

Flag a Model

// User flags a post as "like"
$user = User::find(1);
$post = Post::find(1);

$user->flag($post, 'like');

Unflag a Model

// User removes like from post
$user->unflag($post, 'like');

Check if Flagged

// Check if user has liked the post
if ($user->hasFlagged($post, 'like')) {
    echo "User has liked this post";
}

Get Flag Count

Get the total number of flags for a model:
// Get total likes for a post
$likeCount = $post->flagCount('like');

// Get all flags count (all types)
$totalFlags = $post->flagCount();

Get Flagged Entities NEW

Get all entities flagged by a user (the "other way around" of getFlaggers):
// Get all posts liked by user (using trait method)
$likedPosts = $user->flags('like');

// Get all bookmarked posts (using facade)
$bookmarks = Flag::getFlags($user, 'bookmark');

// Get all entities flagged by user (any type)
$allFlags = $user->flags();

API Reference

Complete reference for all available methods and traits

CanFlag Trait

Add this trait to models that can flag other models.

flag(Model $flagable, string $flagTypeName)

Flags a model with the specified flag type.

Parameters:
$flagable - The model to be flagged
$flagTypeName - The type of flag (e.g., 'like', 'follow')

unflag(Model $flagable, string $flagTypeName)

Removes a flag from a model.

Parameters:
$flagable - The model to unflag
$flagTypeName - The type of flag to remove

hasFlagged(Model $flagable, ?string $flagTypeName = null): bool

Checks if the model has flagged another model.

Parameters:
$flagable - The model to check
$flagTypeName - Optional flag type to check (null checks all types)

flags(?string $flagTypeName = null)

Returns a collection of all entities flagged by this model.

Parameters:
$flagTypeName - Optional flag type to filter by (null returns all flagged entities)
// Get all posts liked by user
$likedPosts = $user->flags('like');

// Get all entities flagged by user (any type)
$allFlags = $user->flags();

flagsRelation()

Returns a morphMany relationship to all flags created by this model (for advanced queries).

Flagable Trait

Add this trait to models that can be flagged by other models.

isFlaggedBy(Model $flagger, ?string $flagTypeName = null): bool

Checks if this model is flagged by another model.

Parameters:
$flagger - The model that might have flagged this one
$flagTypeName - Optional flag type to check

flagCount(?string $flagTypeName = null): int

Returns the total number of flags for this model.

Parameters:
$flagTypeName - Optional flag type to count (null counts all types)

flaggers(string $flagTypeName, string $flaggerModel)

Returns all models that have flagged this model with a specific flag type.

Parameters:
$flagTypeName - The flag type to search for
$flaggerModel - The class name of the flagger model

flags()

Returns a hasManyThrough relationship to all flags for this model.

Flag Facade

Static methods available through the Flag facade for direct access to flagging functionality.

Flag::getFlags(Model $flagger, ?string $flagTypeName = null)

Returns a collection of all entities flagged by the specified model.

Parameters:
$flagger - The model that created the flags
$flagTypeName - Optional flag type to filter by (null returns all flagged entities)
use Sowailem\Flagable\Facades\Flag;

// Get all posts bookmarked by user
$bookmarks = Flag::getFlags($user, 'bookmark');

// Get all entities flagged by user (any type)
$allFlags = Flag::getFlags($user);

Note: The Flag facade also provides static access to all other flagging methods like flag(), unflag(), isFlaggedBy(), getFlagCount(), and getFlaggers().

Default Flag Types

The package comes with these pre-defined flag types:

like
follow
favorite
bookmark
upvote
downvote

Database Architecture

Understanding the sophisticated four-table design

Architecture Overview

The Flagable package uses a sophisticated four-table architecture that provides optimal performance, flexibility, and data integrity. This design allows for efficient querying while maintaining clean relationships between different entities.

Benefits of This Design

  • Eliminates data duplication
  • Optimizes database storage
  • Enables efficient indexing
  • Supports unlimited flag types
  • Maintains referential integrity

Table Relationships

flag_typesflag_links
flag_targetsflag_links
flag_linksflags
flagspolymorphic flaggers

flag_types

Stores all available flag types (like, follow, favorite, etc.)

id Primary Key
name Unique String

flag_targets

Stores model class names that can be flagged

id Primary Key
name Model Class Name

flag_links

Links flag types with target models (junction table)

id Primary Key
flag_type_id Foreign Key
flag_target_id Foreign Key
Unique: (flag_type_id, flag_target_id)

flags

Stores individual flag records with polymorphic relationships

id Primary Key
flag_link_id Foreign Key
flagger_type Polymorphic Type
flagger_id Polymorphic ID
timestamps Created/Updated
Unique: (flag_link_id, flagger_type, flagger_id)
Index: (flagger_type, flagger_id)

How It Works: Example Flow

Here's how the system works when a User likes a Post:

1

Check/Create Flag Type

System ensures "like" exists in flag_types table

2

Check/Create Flag Target

System ensures "App\Models\Post" exists in flag_targets table

3

Check/Create Flag Link

System creates link between "like" type and "Post" target in flag_links table

4

Create Flag Record

System creates the actual flag record in flags table with User's polymorphic relationship