PHPackages                             firevel/firestore-mirror - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. firevel/firestore-mirror

ActiveLibrary[Database &amp; ORM](/categories/database)

firevel/firestore-mirror
========================

Mirror Laravel model inside Firestore collection.

0.0.7(3mo ago)66.7k↓50%1[1 PRs](https://github.com/firevel/firestore-mirror/pulls)MITPHPCI passing

Since Dec 2Pushed 3mo agoCompare

[ Source](https://github.com/firevel/firestore-mirror)[ Packagist](https://packagist.org/packages/firevel/firestore-mirror)[ RSS](/packages/firevel-firestore-mirror/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (7)Dependencies (4)Versions (9)Used By (0)

Laravel Firestore Mirror
========================

[](#laravel-firestore-mirror)

[![Latest Version on Packagist](https://camo.githubusercontent.com/657953a4c0bc660397e0e584de68a59c11b183799230d035b78d977e66862c78/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6669726576656c2f6669726573746f72652d6d6972726f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/firevel/firestore-mirror)[![Total Downloads](https://camo.githubusercontent.com/8229638a0ded28f57f2b5e764c3ea888444e034d4bff66c8d9acfaae07111e69/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6669726576656c2f6669726573746f72652d6d6972726f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/firevel/firestore-mirror)[![CI](https://github.com/firevel/firestore-mirror/actions/workflows/ci.yml/badge.svg)](https://github.com/firevel/firestore-mirror/actions/workflows/ci.yml)

Automatically sync your Laravel Eloquent models to Google Firestore collections in real-time. This package provides a seamless way to mirror your database records to Firestore, enabling powerful real-time features and offline capabilities for your applications.

Features
--------

[](#features)

- 🔄 **Automatic Synchronization**: Changes to your Eloquent models are automatically reflected in Firestore
- 🚀 **Batch Operations**: Efficiently sync entire collections using Firestore's batch API
- 📂 **Multiple Collections**: Mirror a single model to multiple Firestore collections for denormalization
- 🎯 **Flexible Configuration**: Customize collection names, document IDs, and document structure
- 🧩 **Simple Integration**: Just add a trait to your existing Eloquent models
- ⚡ **Performance Optimized**: Uses Firestore batch operations for bulk updates
- 🛠️ **Artisan Command**: Built-in command for bulk mirroring with progress tracking and chunked processing

Requirements
------------

[](#requirements)

- PHP 8.0 or higher
- Laravel 8.0 or higher
- [firevel/firestore](https://github.com/firevel/firestore) package

Installation
------------

[](#installation)

Install the package using Composer:

```
composer require firevel/firestore-mirror
```

Quick Start
-----------

[](#quick-start)

Add the `HasFirestoreMirror` trait to any Eloquent model you want to sync with Firestore:

```
use Firevel\FirestoreMirror\HasFirestoreMirror;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasFirestoreMirror;

    // Optional: Customize the Firestore collection name
    public $firestoreCollection = 'users';

    // Optional: Customize the document structure
    public function toFirestoreDocument()
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at->toIso8601String(),
        ];
    }
}
```

That's it! Your User model will now automatically sync to Firestore whenever you create, update, or delete records.

Configuration
-------------

[](#configuration)

### Customizing Collection Names

[](#customizing-collection-names)

By default, the Firestore collection name matches your model's database table name. You can customize this in two ways:

#### Static Collection Name

[](#static-collection-name)

```
class User extends Model
{
    use HasFirestoreMirror;

    public $firestoreCollection = 'app_users';
}
```

#### Dynamic Collection Name

[](#dynamic-collection-name)

```
class User extends Model
{
    use HasFirestoreMirror;

    public function getFirestoreCollectionName()
    {
        return 'users_' . $this->tenant_id;
    }
}
```

### Customizing Document Structure

[](#customizing-document-structure)

Control exactly what data gets synced to Firestore by overriding the `toFirestoreDocument()` method:

```
public function toFirestoreDocument()
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'role' => $this->role,
        'metadata' => [
            'last_login' => $this->last_login?->toIso8601String(),
            'verified' => $this->email_verified_at !== null,
        ],
        'updated_at' => $this->updated_at->toIso8601String(),
    ];
}
```

### Customizing Document IDs

[](#customizing-document-ids)

By default, the Firestore document ID matches your model's primary key. Override this behavior:

```
public function getFirestoreDocumentId()
{
    return $this->uuid; // Use a UUID field instead
}
```

### Mirroring to Multiple Collections

[](#mirroring-to-multiple-collections)

You can mirror a single model to multiple Firestore collections. This is useful for denormalization patterns common in Firestore, where you might want the same data available in different collections for efficient querying.

#### Using Property

[](#using-property)

```
class User extends Model
{
    use HasFirestoreMirror;

    // Mirror to multiple collections
    public $firestoreCollection = ['users', 'public_profiles'];
}
```

#### Using getFirestoreCollectionName() Method

[](#using-getfirestorecollectionname-method)

```
class User extends Model
{
    use HasFirestoreMirror;

    public function getFirestoreCollectionName()
    {
        return ['users', 'public_profiles', 'search_index'];
    }
}
```

#### Using getFirestoreCollectionNames() Method (Recommended)

[](#using-getfirestorecollectionnames-method-recommended)

```
class User extends Model
{
    use HasFirestoreMirror;

    public function getFirestoreCollectionNames(): array
    {
        return ['users', 'public_profiles'];
    }
}
```

When mirroring to multiple collections:

- All collections receive the same document ID and document structure
- Write and delete operations use Firestore's batch API for atomicity
- If you need different document structures per collection, override `toFirestoreDocument()` with conditional logic

**Priority Order**: If multiple methods are defined, `getFirestoreCollectionNames()` takes precedence over `getFirestoreCollectionName()`, which takes precedence over the `$firestoreCollection` property.

Usage
-----

[](#usage)

### Automatic Syncing

[](#automatic-syncing)

Once you've added the `HasFirestoreMirror` trait, your models will automatically sync to Firestore on these events:

- **Create**: New model instances are added to Firestore
- **Update**: Changes to existing models are synced to Firestore
- **Delete**: Deleted models are removed from Firestore

```
// This will automatically create a document in Firestore
$user = User::create([
    'name' => 'John Doe',
    'email' => 'john@example.com'
]);

// This will automatically update the document in Firestore
$user->update(['name' => 'Jane Doe']);

// This will automatically delete the document from Firestore
$user->delete();
```

### Manual Syncing

[](#manual-syncing)

You can manually sync individual models:

```
$user = User::find(1);
$user->mirrorToFirestore(); // Manually sync to Firestore
```

### Batch Syncing Collections

[](#batch-syncing-collections)

The package provides a powerful `mirrorToFirestore()` collection macro for efficiently syncing multiple models at once using Firestore's batch operations:

```
// Sync all users to Firestore
User::all()->mirrorToFirestore();

// Sync filtered collections
User::where('active', true)->get()->mirrorToFirestore();

// Sync users with relationships loaded
User::with('posts')->get()->mirrorToFirestore();

// Sync paginated results
User::paginate(100)->mirrorToFirestore();
```

The batch operation is atomic - either all documents are synced successfully, or none are.

### Artisan Command for Bulk Mirroring

[](#artisan-command-for-bulk-mirroring)

For large-scale operations or initial data migration, use the included Artisan command to mirror all records of a model to Firestore:

```
# Mirror all users to Firestore
php artisan firestore:mirror "App\Models\User"

# Mirror with custom chunk size (default: 100)
php artisan firestore:mirror "App\Models\User" --chunk=500

# Mirror any model with the HasFirestoreMirror trait
php artisan firestore:mirror "App\Models\Post" --chunk=200
```

**Features:**

- 📊 **Progress Bar**: Real-time progress feedback during the mirror operation
- 🔄 **Chunked Processing**: Processes records in configurable batches to prevent memory issues
- ⚡ **Batch Operations**: Uses Firestore batch API for optimal performance
- ✅ **Validation**: Ensures the model exists and uses the `HasFirestoreMirror` trait

**Example Output:**

```
Starting mirror process for App\Models\User...
Total records to mirror: 1500
1500/1500 [████████████████████████████] 100%
Successfully mirrored 1500 records to Firestore.

```

**When to Use:**

- Initial data migration when setting up Firestore mirroring
- Recovering from sync failures or data inconsistencies
- Re-syncing data after changing `toFirestoreDocument()` structure
- Batch operations on very large collections (thousands+ records)

**Note:** The command respects the `shouldMirrorToFirestore()` method and will skip records that shouldn't be mirrored. For programmatic batch operations within your application code, use the collection macro `->mirrorToFirestore()` instead.

### Deleting from Firestore

[](#deleting-from-firestore)

To manually delete a model from Firestore without deleting it from your database:

```
$user = User::find(1);
$user->deleteFromFirestore();
```

Advanced Usage
--------------

[](#advanced-usage)

### Disabling Syncing Temporarily

[](#disabling-syncing-temporarily)

You can temporarily disable Firestore syncing for specific operations using the `withoutSyncingToFirestore()` method:

```
// Disable syncing for a single operation
User::withoutSyncingToFirestore(function () {
    User::create([
        'name' => 'John Doe',
        'email' => 'john@example.com'
    ]);
});

// Disable syncing for multiple operations
User::withoutSyncingToFirestore(function () {
    // None of these will sync to Firestore
    $user = User::create(['name' => 'Jane']);
    $user->update(['email' => 'jane@example.com']);

    User::find(1)->update(['status' => 'inactive']);
});

// The callback return value is passed through
$user = User::withoutSyncingToFirestore(function () {
    return User::create(['name' => 'Test User']);
});
```

This is particularly useful for:

- Importing large datasets without Firestore overhead
- Running database seeders and factories during testing
- Performing bulk operations that you'll sync manually later
- Temporary data that doesn't need to be mirrored

### Conditional Syncing

[](#conditional-syncing)

The package provides built-in support for conditional syncing. Override the `shouldMirrorToFirestore()` method to control when models should be synced to Firestore:

```
class User extends Model
{
    use HasFirestoreMirror;

    /**
     * Determine if the model should be mirrored to Firestore.
     *
     * @return bool
     */
    public function shouldMirrorToFirestore()
    {
        // Only mirror active users with verified emails
        return $this->is_active && $this->email_verified_at !== null;
    }
}
```

When `shouldMirrorToFirestore()` returns `false`:

- The model will not be synced to Firestore on create/update
- The model will not be deleted from Firestore on deletion
- Both `mirrorToFirestore()` and `deleteFromFirestore()` will return early without making Firestore calls

This is useful for:

- Skipping sync for draft or incomplete records
- Conditional syncing based on user roles or permissions
- Implementing soft-delete patterns where you want to keep Firestore data
- Performance optimization by reducing unnecessary Firestore writes

### Multi-Tenant Applications

[](#multi-tenant-applications)

For multi-tenant applications, you can dynamically set collection names:

```
class Order extends Model
{
    use HasFirestoreMirror;

    public function getFirestoreCollectionName()
    {
        return "tenants/{$this->tenant_id}/orders";
    }
}
```

Testing
-------

[](#testing)

Run the test suite:

```
composer test
```

Run a specific test:

```
vendor/bin/phpunit tests/Unit/HasFirestoreMirrorTest.php
```

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance78

Regular maintenance activity

Popularity29

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~252 days

Recently: every ~353 days

Total

7

Last Release

116d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3ef4a79c6f9a9afe04267a19b98fe0a5a45930c92d08fd720b233ab21ae102ca?d=identicon)[sl0wik](/maintainers/sl0wik)

---

Top Contributors

[![sl0wik](https://avatars.githubusercontent.com/u/2696038?v=4)](https://github.com/sl0wik "sl0wik (27 commits)")

---

Tags

laravelmodelfirestorefirevel

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/firevel-firestore-mirror/health.svg)

```
[![Health](https://phpackages.com/badges/firevel-firestore-mirror/health.svg)](https://phpackages.com/packages/firevel-firestore-mirror)
```

###  Alternatives

[shiftonelabs/laravel-cascade-deletes

Adds application level cascading deletes to Eloquent Models.

163632.1k2](/packages/shiftonelabs-laravel-cascade-deletes)[highsolutions/eloquent-sequence

A Laravel package for easy creation and management sequence support for Eloquent models with elastic configuration.

121130.3k](/packages/highsolutions-eloquent-sequence)[firevel/firequent

Limited implementation of Eloquent based on Firestore.

267.1k](/packages/firevel-firequent)[phaza/single-table-inheritance

Single Table Inheritance Trait

1515.8k](/packages/phaza-single-table-inheritance)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
